Updated the 'extralibs' dir's files from upstream repo.
This commit is contained in:
parent
240e26c130
commit
07cd32ecb5
16 changed files with 4021 additions and 776 deletions
158
inc/extralibs/ch20x_30x_flash.h
Normal file
158
inc/extralibs/ch20x_30x_flash.h
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
Flash library for v20x/v30x. Use the following functions:
|
||||||
|
|
||||||
|
* ch20x_30x_flash_cmd_read(): Read from flash
|
||||||
|
* ch20x_30x_flash_cmd_write(): Write to flash
|
||||||
|
* ch20x_30x_flash_cmd_erase(): Erase flash
|
||||||
|
* ch20x_30x_flash_cmd_verify(): Verify written data.
|
||||||
|
|
||||||
|
Flash erase operations must be in page granularity: addr must be page aligned,
|
||||||
|
and length must be multiple of the page size (256 bytes).
|
||||||
|
|
||||||
|
For flash write operations, addr must be page aligned, and both buf and len
|
||||||
|
must be aligned to 32 bits.
|
||||||
|
|
||||||
|
Read and verify operations do not have alignment restrictions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h> // For memcmp()
|
||||||
|
|
||||||
|
#include "ch32fun.h"
|
||||||
|
|
||||||
|
#define CH20X_30X_FLASH_PAGE_LEN 256
|
||||||
|
#define CH20X_30X_FLASH_PAGE_U32LEN (CH20X_30X_FLASH_PAGE_LEN / sizeof(uint32_t))
|
||||||
|
#define CH20X_30X_FLASH_ALIGN_MASK (CH20X_30X_FLASH_PAGE_LEN - 1)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FLASH_OK = 0, // Success
|
||||||
|
FLASH_ERR_PARAM, // Parameter error (check alignment!)
|
||||||
|
FLASH_ERR_CLK, // Clock is too high (use HPRE or lower system clock below 120MHz)
|
||||||
|
FLASH_ERR_VERIFY, // Verify has failed
|
||||||
|
FLASH_ERR_PROTECT, // Write protection error
|
||||||
|
};
|
||||||
|
|
||||||
|
void _ch20x_30x_flash_unlock(void)
|
||||||
|
{
|
||||||
|
__disable_irq();
|
||||||
|
FLASH->KEYR = FLASH_KEY1;
|
||||||
|
FLASH->KEYR = FLASH_KEY2;
|
||||||
|
|
||||||
|
FLASH->MODEKEYR = FLASH_KEY1;
|
||||||
|
FLASH->MODEKEYR = FLASH_KEY2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ch20x_30x_flash_lock(void)
|
||||||
|
{
|
||||||
|
FLASH->CTLR = FLASH_CTLR_LOCK | FLASH_CTLR_FAST_LOCK;
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch20x_30x_flash_cmd_read(uintptr_t addr, uint8_t *buf, uint32_t len)
|
||||||
|
{
|
||||||
|
memcpy(buf, (void*)addr, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t _ch20x_30x_flash_busy_poll(void)
|
||||||
|
{
|
||||||
|
while (FLASH->STATR & FLASH_STATR_BSY);
|
||||||
|
|
||||||
|
const uint32_t err = FLASH->STATR & FLASH_STATR_WRPRTERR;
|
||||||
|
// Clear status flags (EOP/WRPRTERR)
|
||||||
|
FLASH->STATR = FLASH_STATR_EOP | FLASH_STATR_WRPRTERR;
|
||||||
|
|
||||||
|
return err ? FLASH_ERR_PROTECT : FLASH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes one page at most
|
||||||
|
uint32_t _ch20x_30x_flash_page_write(uintptr_t addr, const uint32_t *data, uint32_t u32len)
|
||||||
|
{
|
||||||
|
volatile uint32_t *dst = (volatile uint32_t*)addr;
|
||||||
|
|
||||||
|
FLASH->CTLR = CR_PAGE_PG; // FTPG, quick program 64-dword page
|
||||||
|
// Write data to buffer (must point to appropriate address
|
||||||
|
for (uint_fast8_t i = 0; i < u32len; i++) {
|
||||||
|
dst[i] = data[i];
|
||||||
|
while (FLASH->STATR & 0x02); // WRBSY
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform buffer to flash program
|
||||||
|
FLASH->CTLR = CR_PAGE_PG | CR_PG_STRT;
|
||||||
|
|
||||||
|
// Busy poll and return
|
||||||
|
return _ch20x_30x_flash_busy_poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// addr must be page aligned (256 bytes).
|
||||||
|
// buf and len must be aligned to 32 bits
|
||||||
|
uint32_t ch20x_30x_flash_cmd_write(uintptr_t addr, const uint8_t *buf, uint32_t len )
|
||||||
|
{
|
||||||
|
uint32_t err = FLASH_OK;
|
||||||
|
|
||||||
|
// Check SYSCLK / HB prescaler is not greater than 120 MHz
|
||||||
|
#if (FUNCONF_SYSTEM_CORE_CLOCK > 120000000)
|
||||||
|
if (!(RCC->CFGR0 & RCC_HPRE_3)) {
|
||||||
|
return FLASH_ERR_CLK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (addr & CH20X_30X_FLASH_ALIGN_MASK || (uintptr_t)buf & 3 || len & 3) {
|
||||||
|
return FLASH_ERR_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ch20x_30x_flash_unlock();
|
||||||
|
while (!err && len) {
|
||||||
|
const uint32_t to_write = len < CH20X_30X_FLASH_PAGE_LEN ?
|
||||||
|
len : CH20X_30X_FLASH_PAGE_LEN;
|
||||||
|
err = _ch20x_30x_flash_page_write(addr, (uint32_t*)buf,
|
||||||
|
to_write / sizeof(uint32_t));
|
||||||
|
addr += to_write;
|
||||||
|
buf += to_write;
|
||||||
|
len -= to_write;
|
||||||
|
}
|
||||||
|
FLASH->CTLR = 0; // Clear FTPG
|
||||||
|
_ch20x_30x_flash_lock();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t _ch20x_30x_flash_page_erase(uintptr_t addr)
|
||||||
|
{
|
||||||
|
FLASH->CTLR = CR_PAGE_ER; // FTER, erase a full page
|
||||||
|
FLASH->ADDR = addr;
|
||||||
|
FLASH->CTLR = CR_STRT_Set | CR_PAGE_ER;
|
||||||
|
|
||||||
|
// Busy poll and return
|
||||||
|
return _ch20x_30x_flash_busy_poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
// addr and len must be page aligned (256 bytes)
|
||||||
|
uint32_t ch20x_30x_flash_cmd_erase(uintptr_t addr, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t err = FLASH_OK;
|
||||||
|
|
||||||
|
// Check SYSCLK / HB prescaler is not greater than 120 MHz
|
||||||
|
#if (FUNCONF_SYSTEM_CORE_CLOCK > 120000000)
|
||||||
|
if (!(RCC->CFGR0 & RCC_HPRE_3)) {
|
||||||
|
return FLASH_ERR_CLK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (addr & CH20X_30X_FLASH_ALIGN_MASK || len & CH20X_30X_FLASH_ALIGN_MASK) {
|
||||||
|
return FLASH_ERR_PARAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t pages = len / CH20X_30X_FLASH_PAGE_LEN;
|
||||||
|
_ch20x_30x_flash_unlock();
|
||||||
|
for (uint32_t i = 0; !err && i < pages; i++) {
|
||||||
|
err = _ch20x_30x_flash_page_erase(addr);
|
||||||
|
addr += CH20X_30X_FLASH_PAGE_LEN;
|
||||||
|
}
|
||||||
|
FLASH->CTLR = 0; // Clear FTER
|
||||||
|
_ch20x_30x_flash_lock();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ch20x_30x_flash_cmd_verify(uintptr_t addr, uint8_t *buf, int len)
|
||||||
|
{
|
||||||
|
return memcmp((void*)addr, buf, len) ? FLASH_ERR_VERIFY : FLASH_OK;
|
||||||
|
}
|
||||||
264
inc/extralibs/ch32v00x_touch.h
Normal file
264
inc/extralibs/ch32v00x_touch.h
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
#ifndef _CH32V00X_TOUCH_H
|
||||||
|
#define _CH32V00X_TOUCH_H
|
||||||
|
|
||||||
|
/** ADC-based Capactive Touch Control.
|
||||||
|
|
||||||
|
see cap_touch_adc.c for an example.
|
||||||
|
|
||||||
|
// Enable GPIOD, C and ADC
|
||||||
|
RCC->APB2PCENR |= RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1;
|
||||||
|
InitTouchADC();
|
||||||
|
|
||||||
|
// Then do this any time you want to read some touches.
|
||||||
|
sum[0] += ReadTouchPin( GPIOA, 2, 0, iterations );
|
||||||
|
sum[1] += ReadTouchPin( GPIOA, 1, 1, iterations );
|
||||||
|
sum[2] += ReadTouchPin( GPIOC, 4, 2, iterations );
|
||||||
|
sum[3] += ReadTouchPin( GPIOD, 2, 3, iterations );
|
||||||
|
sum[4] += ReadTouchPin( GPIOD, 3, 4, iterations );
|
||||||
|
sum[5] += ReadTouchPin( GPIOD, 5, 5, iterations );
|
||||||
|
sum[6] += ReadTouchPin( GPIOD, 6, 6, iterations );
|
||||||
|
sum[7] += ReadTouchPin( GPIOD, 4, 7, iterations );
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define TOUCH_ADC_SAMPLE_TIME 2 // Tricky: Don't change this without a lot of experimentation.
|
||||||
|
|
||||||
|
// Can either be 0 or 1.
|
||||||
|
// If 0: Measurement low and rises high. So more pressed is smaller number.
|
||||||
|
// If 1: Higher number = harder press. Good to pair with TOUCH_FLAT.
|
||||||
|
// If you are doing more prox, use mode 0, otherwise, use mode 1.
|
||||||
|
#define TOUCH_SLOPE 1
|
||||||
|
|
||||||
|
// If you set this to 1, it will glitch the line, so it will only read
|
||||||
|
// anything reasonable if the capacitance can overcome that initial spike.
|
||||||
|
// Typically, it seems if you use this you probbly don't need to do
|
||||||
|
// any pre-use calibration.
|
||||||
|
#define TOUCH_FLAT 0
|
||||||
|
|
||||||
|
// Macro used for force-alingining ADC timing
|
||||||
|
#define FORCEALIGNADC \
|
||||||
|
asm volatile( \
|
||||||
|
"\n\
|
||||||
|
.balign 4\n\
|
||||||
|
andi a2, %[cyccnt], 3\n\
|
||||||
|
c.slli a2, 1\n\
|
||||||
|
c.addi a2, 12\n\
|
||||||
|
auipc a1, 0\n\
|
||||||
|
c.add a2, a1\n\
|
||||||
|
jalr a2, 1\n\
|
||||||
|
.long 0x00010001\n\
|
||||||
|
.long 0x00010001\n\
|
||||||
|
"\
|
||||||
|
:: [cyccnt]"r"(SysTick->CNT) : "a1", "a2"\
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
static void InitTouchADC( );
|
||||||
|
void InitTouchADC( )
|
||||||
|
{
|
||||||
|
#ifdef CH32V003
|
||||||
|
|
||||||
|
#define EXTRA_ADC_SETUP_ONLY_ON_00X
|
||||||
|
|
||||||
|
|
||||||
|
// ADCCLK = 24 MHz => RCC_ADCPRE = 0: divide sys clock by 2
|
||||||
|
RCC->CFGR0 &= ~(0x1F<<11);
|
||||||
|
|
||||||
|
// Set up single conversion on chl 2
|
||||||
|
ADC1->RSQR1 = 0;
|
||||||
|
ADC1->RSQR2 = 0;
|
||||||
|
|
||||||
|
// turn on ADC and set rule group to sw trig
|
||||||
|
ADC1->CTLR2 |= ADC_ADON | ADC_EXTSEL;
|
||||||
|
|
||||||
|
// Reset calibration
|
||||||
|
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||||
|
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||||
|
|
||||||
|
// Calibrate
|
||||||
|
ADC1->CTLR2 |= ADC_CAL;
|
||||||
|
while(ADC1->CTLR2 & ADC_CAL);
|
||||||
|
|
||||||
|
#elif defined( CH32V00x )
|
||||||
|
|
||||||
|
#define EXTRA_ADC_SETUP_ONLY_ON_00X ADC1->CTLR2 = ADC_ADON | ADC_EXTSEL;
|
||||||
|
|
||||||
|
// ADCCLK = 48 MHz => RCC_ADCPRE divide by 2
|
||||||
|
// RCC_CFGR0_ADC_CLK_MODE = 0 -- HB clock divides to make ADC clock -- vs 1 = No ADC Division.
|
||||||
|
// RCC_CFGR0_ADC_CLK_ADJ = 0 -- 1/2 duty cycle high level ADC clock
|
||||||
|
RCC->CFGR0 = (RCC->CFGR0 & ~(RCC_ADCPRE | RCC_CFGR0_ADC_CLK_MODE | RCC_HPRE));
|
||||||
|
|
||||||
|
// Set up single conversion on chl 2
|
||||||
|
ADC1->RSQR1 = 0;
|
||||||
|
ADC1->RSQR2 = 0;
|
||||||
|
|
||||||
|
// Turn on ADC module Not sure why it needs to be done twice.
|
||||||
|
ADC1->CTLR2 = ADC_ADON | ADC_EXTSEL_SWSTART;
|
||||||
|
ADC1->CTLR2 = ADC_ADON | ADC_EXTSEL_SWSTART;
|
||||||
|
|
||||||
|
// enable scanning
|
||||||
|
ADC1->CTLR1 = ADC_SCAN | ADC_BUFEN;
|
||||||
|
|
||||||
|
// Reset calibration
|
||||||
|
ADC1->CTLR2 |= ADC_RSTCAL;
|
||||||
|
while(ADC1->CTLR2 & ADC_RSTCAL);
|
||||||
|
|
||||||
|
// Calibrate
|
||||||
|
ADC1->CTLR2 |= ADC_CAL;
|
||||||
|
while(ADC1->CTLR2 & ADC_CAL);
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error ADC Code for touch not written for this chip.
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run from RAM to get even more stable timing.
|
||||||
|
// This function call takes about 8.1uS to execute.
|
||||||
|
static uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||||
|
uint32_t ReadTouchPin( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
FORCEALIGNADC
|
||||||
|
ADC1->RSQR3 = adcno;
|
||||||
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
uint32_t CFGBASE = io->CFGLR & (~(0xf<<(4*portpin)));
|
||||||
|
uint32_t CFGFLOAT = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | CFGBASE;
|
||||||
|
uint32_t CFGDRIVE = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | CFGBASE;
|
||||||
|
|
||||||
|
// If we run multiple times with slightly different wait times, we can
|
||||||
|
// reduce the impact of the ADC's DNL.
|
||||||
|
|
||||||
|
|
||||||
|
#if TOUCH_FLAT == 1
|
||||||
|
#define RELEASEIO io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); io->CFGLR = CFGFLOAT;
|
||||||
|
#else
|
||||||
|
#define RELEASEIO io->CFGLR = CFGFLOAT; io->BSHR = 1<<(portpin+16*TOUCH_SLOPE);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define INNER_LOOP( n ) \
|
||||||
|
{ \
|
||||||
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
|
__disable_irq(); \
|
||||||
|
FORCEALIGNADC \
|
||||||
|
\
|
||||||
|
EXTRA_ADC_SETUP_ONLY_ON_00X \
|
||||||
|
\
|
||||||
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
|
\
|
||||||
|
ADD_N_NOPS( n ) \
|
||||||
|
\
|
||||||
|
RELEASEIO \
|
||||||
|
\
|
||||||
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
|
interrupts run */ \
|
||||||
|
__enable_irq(); \
|
||||||
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
|
io->CFGLR = CFGDRIVE; \
|
||||||
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
|
ret += ADC1->RDATAR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < iterations; i++ )
|
||||||
|
{
|
||||||
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
|
INNER_LOOP( 0 );
|
||||||
|
INNER_LOOP( 2 );
|
||||||
|
INNER_LOOP( 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run from RAM to get even more stable timing.
|
||||||
|
// This function call takes about 8.1uS to execute.
|
||||||
|
static uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations ) __attribute__((noinline, section(".srodata")));
|
||||||
|
uint32_t ReadTouchPinSafe( GPIO_TypeDef * io, int portpin, int adcno, int iterations )
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
ADC1->RSQR3 = adcno;
|
||||||
|
ADC1->SAMPTR2 = TOUCH_ADC_SAMPLE_TIME<<(3*adcno);
|
||||||
|
|
||||||
|
// If we run multiple times with slightly different wait times, we can
|
||||||
|
// reduce the impact of the ADC's DNL.
|
||||||
|
|
||||||
|
#define INNER_LOOP_SAFE( n ) \
|
||||||
|
{ \
|
||||||
|
/* Only lock IRQ for a very narrow window. */ \
|
||||||
|
__disable_irq(); \
|
||||||
|
\
|
||||||
|
FORCEALIGNADC \
|
||||||
|
\
|
||||||
|
EXTRA_ADC_SETUP_ONLY_ON_00X \
|
||||||
|
\
|
||||||
|
/* Tricky - we start the ADC BEFORE we transition the pin. By doing \
|
||||||
|
this We are catching it onthe slope much more effectively. */ \
|
||||||
|
ADC1->CTLR2 = ADC_SWSTART | ADC_ADON | ADC_EXTSEL; \
|
||||||
|
\
|
||||||
|
ADD_N_NOPS( n ) \
|
||||||
|
\
|
||||||
|
io->CFGLR = ((GPIO_CFGLR_IN_PUPD)<<(4*portpin)) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
|
io->BSHR = 1<<(portpin+16*TOUCH_SLOPE); \
|
||||||
|
\
|
||||||
|
/* Sampling actually starts here, somewhere, so we can let other \
|
||||||
|
interrupts run */ \
|
||||||
|
__enable_irq(); \
|
||||||
|
while(!(ADC1->STATR & ADC_EOC)); \
|
||||||
|
__disable_irq(); \
|
||||||
|
io->CFGLR = (GPIO_CFGLR_OUT_2Mhz_PP)<<(4*portpin) | (io->CFGLR & (~(0xf<<(4*portpin)))); \
|
||||||
|
__enable_irq(); \
|
||||||
|
io->BSHR = 1<<(portpin+(16*(1-TOUCH_SLOPE))); \
|
||||||
|
ret += ADC1->RDATAR; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < iterations; i++ )
|
||||||
|
{
|
||||||
|
// Wait a variable amount of time based on loop iteration, in order
|
||||||
|
// to get a variety of RC points and minimize DNL.
|
||||||
|
|
||||||
|
INNER_LOOP_SAFE( 0 );
|
||||||
|
INNER_LOOP_SAFE( 2 );
|
||||||
|
INNER_LOOP_SAFE( 4 );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2023 Valve Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
311
inc/extralibs/ch5xx_flash.h
Normal file
311
inc/extralibs/ch5xx_flash.h
Normal file
|
|
@ -0,0 +1,311 @@
|
||||||
|
/*
|
||||||
|
Flash library for ch5xx
|
||||||
|
|
||||||
|
The FUNCONF_CH5XXFLASHLIB_SECTION macro is available for tight RAM situations,
|
||||||
|
some critical functions need to be ran from RAM. This takes 480 bytes when
|
||||||
|
compiled on my machine. With the macro you could do something like this:
|
||||||
|
|
||||||
|
in funconfig.h:
|
||||||
|
#define FUNCONF_CH5XXFLASHLIB_SECTION __attribute__( ( section( ".manual_ram" ) ) )
|
||||||
|
|
||||||
|
in the project's linker file:
|
||||||
|
.manual_ram_inflash :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_flash_manual_ram_start = .);
|
||||||
|
} >FLASH AT>FLASH
|
||||||
|
|
||||||
|
.manual_ram :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_manual_ram_vma_start = .);
|
||||||
|
*(.manual_ram*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
PROVIDE(_manual_ram_vma_end = .);
|
||||||
|
} >RAM AT>FLASH
|
||||||
|
|
||||||
|
in any C source:
|
||||||
|
extern const uint32_t _manual_ram_vma_start;
|
||||||
|
extern const uint32_t _manual_ram_vma_end;
|
||||||
|
extern const uint32_t _flash_manual_ram_start;
|
||||||
|
|
||||||
|
void load_manual_ram_section( void )
|
||||||
|
{
|
||||||
|
const size_t manual_ram_size = (size_t)( &_manual_ram_vma_end - &_manual_ram_vma_start );
|
||||||
|
memcpy( (void *)&_manual_ram_vma_start, (void *)&_flash_manual_ram_start, manual_ram_size );
|
||||||
|
}
|
||||||
|
|
||||||
|
// when you don't use the function, you can use the ram area as scratch
|
||||||
|
uint8_t *scratch = (uint8_t *)&_manual_ram_vma_start;
|
||||||
|
|
||||||
|
// when need to write to flash:
|
||||||
|
load_manual_ram_section();
|
||||||
|
|
||||||
|
// all ch5xx_flash_cmd_* work now:
|
||||||
|
ch5xx_flash_cmd_erase(...);
|
||||||
|
|
||||||
|
// when done, just continue using the "scratch" buffer for whatever
|
||||||
|
*/
|
||||||
|
#ifdef FUNCONF_CH5XXFLASHLIB_SECTION
|
||||||
|
#undef __HIGH_CODE
|
||||||
|
#define __HIGH_CODE FUNCONF_CH5XXFLASHLIB_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
uint8_t ch5xx_flash_rom_in() {
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
return R8_FLASH_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_out(uint8_t val) {
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
R8_FLASH_DATA = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_begin(uint8_t cmd) {
|
||||||
|
R8_FLASH_CTRL = 0;
|
||||||
|
R8_FLASH_CTRL = 0x05;
|
||||||
|
asm volatile ("nop\nnop");
|
||||||
|
R8_FLASH_DATA = cmd;
|
||||||
|
if(cmd == 0xff) {
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
R8_FLASH_DATA = cmd;
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_end() {
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
R8_FLASH_CTRL = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_open(uint8_t op) {
|
||||||
|
__disable_irq();
|
||||||
|
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_GLOB_ROM_CFG = op;
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
R8_FLASH_CTRL = 0x04; // close
|
||||||
|
ch5xx_flash_rom_begin(0xff);
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_open_read() {
|
||||||
|
ch5xx_flash_rom_open(RB_ROM_CTRL_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_open_erase_write() {
|
||||||
|
ch5xx_flash_rom_open(RB_ROM_CTRL_EN | RB_ROM_CODE_WE);
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_close() {
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_GLOB_ROM_CFG &= RB_ROM_CTRL_EN;
|
||||||
|
);
|
||||||
|
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
void ch5xx_flash_rom_addr(uint8_t cmd, uint32_t addr) {
|
||||||
|
uint8_t repeat = 5;
|
||||||
|
if((cmd & 0xbf) != 0x0b) {
|
||||||
|
ch5xx_flash_rom_begin(0x06);
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
repeat = 3;
|
||||||
|
}
|
||||||
|
ch5xx_flash_rom_begin(cmd);
|
||||||
|
for(int i = 0; i < repeat; i++) {
|
||||||
|
ch5xx_flash_rom_out((uint8_t)(addr >> 0x10));
|
||||||
|
addr <<= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__HIGH_CODE
|
||||||
|
uint8_t ch5xx_flash_rom_wait() {
|
||||||
|
uint8_t status;
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
for(int i = 0; i < 524288; i++) {
|
||||||
|
ch5xx_flash_rom_begin(0x05);
|
||||||
|
ch5xx_flash_rom_in();
|
||||||
|
status = ch5xx_flash_rom_in();
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
if(!(status & 0x01)) { // check write in progress bit
|
||||||
|
return status | 0x01;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0; // timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_unlock(uint8_t cmd) {
|
||||||
|
// cmd: 0 - unlock all, 0x44 - lock boot code, 0x50 - lock all code and flash, 0x3c - lock something, unclear what exactly
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
ch5xx_flash_rom_wait();
|
||||||
|
ch5xx_flash_rom_begin(0x06);
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
ch5xx_flash_rom_begin(0x01);
|
||||||
|
ch5xx_flash_rom_out(cmd);
|
||||||
|
ch5xx_flash_rom_out(0x02);
|
||||||
|
ch5xx_flash_rom_wait();
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_reset() {
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
ch5xx_flash_rom_begin(0x66);
|
||||||
|
ch5xx_flash_rom_end();
|
||||||
|
ch5xx_flash_rom_begin(0x99);
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_read(uint32_t addr, uint8_t *buf, int len) {
|
||||||
|
uint32_t *buf32 = (uint32_t*)buf;
|
||||||
|
int len32 = (len +3) >> 2;
|
||||||
|
|
||||||
|
for(int i = 0; i < len32; i++) {
|
||||||
|
buf32[i] = *((uint32_t*)addr);
|
||||||
|
addr += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ch5xx_flash_cmd_write(uint32_t addr, uint8_t *buf, int len ) {
|
||||||
|
uint32_t *buf32 = (uint32_t*)buf;
|
||||||
|
int len32 = (len +3) >> 2;
|
||||||
|
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
|
||||||
|
while(len32 > 0) {
|
||||||
|
ch5xx_flash_rom_addr(0x02, addr);
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
uint32_t data = *buf32++;
|
||||||
|
R32_FLASH_DATA = data;
|
||||||
|
for(int i = 4; i > 0; i--) {
|
||||||
|
while((int8_t)R8_FLASH_CTRL < 0);
|
||||||
|
R8_FLASH_CTRL = 0x15;
|
||||||
|
}
|
||||||
|
|
||||||
|
len32--;
|
||||||
|
addr += 4;
|
||||||
|
// Check for page boundary (typically 256 bytes)
|
||||||
|
if (len32 == 0 || (addr & 0xff) == 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ch5xx_flash_rom_wait() == 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ch5xx_flash_cmd_erase(uint32_t addr, int len) {
|
||||||
|
addr &= 0xfffff000; // start at a Sector boundary
|
||||||
|
len = (len + (addr & 0xfff) + 0xfff) & 0xfffff000; // adjust length to Sector boundaries
|
||||||
|
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
uint32_t step;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
uint8_t cmd;
|
||||||
|
if (len >= 65536 && !(addr & (65536 -1))) {
|
||||||
|
cmd = 0xd8; // Block Erase
|
||||||
|
step = 65536;
|
||||||
|
}
|
||||||
|
#ifdef CH570_CH572
|
||||||
|
else if (len >= 32768 && !(addr & (32768 -1))) {
|
||||||
|
cmd = 0x52; // Half-Block Erase
|
||||||
|
step = 32768;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmd = 0x20; // Sector Erase
|
||||||
|
step = 4096;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
else if (len >= 4096 && (addr & (4096 -1))) {
|
||||||
|
cmd = 0x20; // Sector Erase
|
||||||
|
step = 4096;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmd = 0x81; // Page Erase
|
||||||
|
step = 256;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ch5xx_flash_rom_addr(cmd, addr);
|
||||||
|
if (ch5xx_flash_rom_wait() == 0) {
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
return (uint32_t)-1;
|
||||||
|
}
|
||||||
|
addr += step;
|
||||||
|
len -= step;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ch5xx_flash_cmd_verify(uint32_t addr, uint8_t *buf, int len) {
|
||||||
|
uint32_t *buf32 = (uint32_t*)buf;
|
||||||
|
int len32 = (len +3) >> 2;
|
||||||
|
|
||||||
|
ch5xx_flash_rom_open_read();
|
||||||
|
ch5xx_flash_rom_addr(0x0b, addr); // Fast Read command
|
||||||
|
|
||||||
|
for (int i = 0; i < len32; i++) {
|
||||||
|
ch5xx_flash_rom_in(); // Dummy/Data read
|
||||||
|
if ((i & 0x03) == 0) {
|
||||||
|
if (R32_FLASH_DATA != *buf32++) {
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_powerup() {
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
ch5xx_flash_rom_begin(0xab);
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_powerdown() {
|
||||||
|
ch5xx_flash_rom_open_erase_write();
|
||||||
|
ch5xx_flash_rom_begin(0xb9);
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ch5xx_flash_cmd_get_rom_info(uint32_t addr, uint8_t *buf) {
|
||||||
|
uint32_t *buf32 = (uint32_t*)buf;
|
||||||
|
|
||||||
|
ch5xx_flash_rom_open_read();
|
||||||
|
ch5xx_flash_rom_addr(0x0b, addr);
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ch5xx_flash_rom_in();
|
||||||
|
if(i == 3) {
|
||||||
|
buf32[0] = R32_FLASH_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t val = R32_FLASH_DATA;
|
||||||
|
if (!((addr << 18) & 0x80000000)) {
|
||||||
|
buf32[1] = val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
((uint16_t*)buf32)[2] = (uint16_t)val; // Store 16-bit at offset 4
|
||||||
|
}
|
||||||
|
ch5xx_flash_rom_close();
|
||||||
|
}
|
||||||
121
inc/extralibs/ch5xx_lowpower.h
Normal file
121
inc/extralibs/ch5xx_lowpower.h
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Low Power Sleep and Idle library for ch5xx
|
||||||
|
*/
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "rtc.h"
|
||||||
|
|
||||||
|
void LSIEnable() {
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
#ifdef CH570_CH572
|
||||||
|
R8_LSI_CONFIG |= RB_CLK_LSI_PON; //turn on LSI
|
||||||
|
#else
|
||||||
|
R8_CK32K_CONFIG &= ~(RB_CLK_OSC32K_XT | RB_CLK_XT32K_PON); // turn off LSE
|
||||||
|
R8_CK32K_CONFIG |= RB_CLK_INT32K_PON; // turn on LSI
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCDCEnable() {
|
||||||
|
#ifndef CH570_CH572 // CH570/2 has no DCDC.
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R16_AUX_POWER_ADJ |= RB_DCDC_CHARGE;
|
||||||
|
R16_POWER_PLAN |= RB_PWR_DCDC_PRE;
|
||||||
|
);
|
||||||
|
|
||||||
|
RTC_WAIT_TICKS(2);
|
||||||
|
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R16_POWER_PLAN |= RB_PWR_DCDC_EN;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SleepInit() {
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_RTC_MODE_CTRL |= RB_RTC_TRIG_EN; //enable RTC trigger
|
||||||
|
R8_SLP_WAKE_CTRL |= RB_SLP_RTC_WAKE; // enable wakeup control
|
||||||
|
);
|
||||||
|
NVIC_EnableIRQ(RTC_IRQn);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter idle state
|
||||||
|
void LowPowerIdleWFI() {
|
||||||
|
NVIC->SCTLR &= ~(1 << 2); // don't deep sleep
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowPowerIdle(uint32_t cyc) {
|
||||||
|
RTC_setAlarm(cyc);
|
||||||
|
LowPowerIdleWFI();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This macro defines which power pin
|
||||||
|
// to use. If not defined correctly, sleep current
|
||||||
|
// will be higher than expected.
|
||||||
|
#ifndef FUNCONF_POWERED_BY_V5PIN
|
||||||
|
#define FUNCONF_POWERED_BY_V5PIN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void LowPowerSleepWFI(uint16_t power_plan) {
|
||||||
|
#ifdef CH570_CH572
|
||||||
|
#if (FUNCONF_POWERED_BY_V5PIN == 1)
|
||||||
|
power_plan |= RB_PWR_LDO5V_EN;
|
||||||
|
#endif
|
||||||
|
#if ( CLK_SOURCE_CH5XX == CLK_SOURCE_PLL_75MHz ) || ( CLK_SOURCE_CH5XX == CLK_SOURCE_PLL_100MHz )
|
||||||
|
//if system clock is higher than 60Mhz, it need to be reduced before sleep.
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_CLK_SYS_CFG = CLK_SOURCE_PLL_60MHz;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#else // !570/2
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_BAT_DET_CTRL = 0;
|
||||||
|
R8_XT32K_TUNE = (R16_RTC_CNT_32K > 0x3fff) ? (R8_XT32K_TUNE & 0xfc) | 0x01 : R8_XT32K_TUNE;
|
||||||
|
R8_XT32M_TUNE = (R8_XT32M_TUNE & 0xfc) | 0x03;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NVIC->SCTLR |= (1 << 2); //deep sleep
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_SLP_POWER_CTRL |= RB_RAM_RET_LV;
|
||||||
|
R16_POWER_PLAN = RB_PWR_PLAN_EN | RB_PWR_CORE | power_plan;
|
||||||
|
R8_PLL_CONFIG |= (1 << 5);
|
||||||
|
);
|
||||||
|
|
||||||
|
__WFI();
|
||||||
|
|
||||||
|
#ifdef CH570_CH572
|
||||||
|
#if ( CLK_SOURCE_CH5XX == CLK_SOURCE_PLL_75MHz ) || ( CLK_SOURCE_CH5XX == CLK_SOURCE_PLL_100MHz )
|
||||||
|
//machine delay for a while.
|
||||||
|
uint16_t i = 400;
|
||||||
|
do {
|
||||||
|
asm volatile("nop");
|
||||||
|
} while(i--);
|
||||||
|
|
||||||
|
//get system clock back to normal
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R8_CLK_SYS_CFG = CLK_SOURCE_CH5XX;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R16_POWER_PLAN &= ~RB_XT_PRE_EN;
|
||||||
|
R8_PLL_CONFIG &= ~(1 << 5);
|
||||||
|
R8_XT32M_TUNE = (R8_XT32M_TUNE & 0xfc) | 0x01;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowPowerSleep(uint32_t cyc, uint16_t power_plan) {
|
||||||
|
RTC_setAlarm(cyc);
|
||||||
|
LowPowerSleepWFI(power_plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LowPower(uint32_t time, uint16_t power_plan) {
|
||||||
|
if( time > 500 ) {
|
||||||
|
LowPowerSleep( time, power_plan );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LowPowerIdle( time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "fsusb.h"
|
#include "fsusb.h"
|
||||||
#include "ch32fun.h"
|
#include "ch32fun.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifdef __DMA_SAFE
|
#ifdef __DMA_SAFE
|
||||||
// CH573 needs all buffers that will touch DMA be allocated at specific memory location
|
// CH573 needs all buffers that will touch DMA be allocated at specific memory location
|
||||||
|
|
@ -11,6 +12,12 @@ __DMA_SAFE
|
||||||
struct _USBState USBFSCTX;
|
struct _USBState USBFSCTX;
|
||||||
volatile uint8_t usb_debug = 0;
|
volatile uint8_t usb_debug = 0;
|
||||||
|
|
||||||
|
#if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF
|
||||||
|
|
||||||
|
uint8_t usb_inputbuffer[USBFS_PACKET_SIZE]; // this can be extended if polling rate is low
|
||||||
|
int usb_inbuf_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined CH5xx && FUSB_USE_DMA7_COPYs
|
#if !defined CH5xx && FUSB_USE_DMA7_COPYs
|
||||||
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len )
|
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len )
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +52,10 @@ static inline void copyBufferComplete() { while( DMA1_Channel7->CNTR ); }
|
||||||
#define USBFS_IRQHandler USB_IRQHandler
|
#define USBFS_IRQHandler USB_IRQHandler
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ANYPRINTF (defined( FUNCONF_USE_DEBUGPRINTF ) && FUNCONF_USE_DEBUGPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_UARTPRINTF ) && FUNCONF_USE_UARTPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF)
|
||||||
|
|
||||||
#if FUSB_USE_HPE
|
#if FUSB_USE_HPE
|
||||||
// There is an issue with some registers apparently getting lost with HPE, just do it the slow way.
|
// There is an issue with some registers apparently getting lost with HPE, just do it the slow way.
|
||||||
void USBFS_IRQHandler() __attribute__((section(".text.vector_handler"))) __attribute((interrupt));
|
void USBFS_IRQHandler() __attribute__((section(".text.vector_handler"))) __attribute((interrupt));
|
||||||
|
|
@ -70,24 +81,25 @@ void USBFS_IRQHandler()
|
||||||
int len = 0;
|
int len = 0;
|
||||||
struct _USBState * ctx = &USBFSCTX;
|
struct _USBState * ctx = &USBFSCTX;
|
||||||
uint8_t * ctrl0buff = CTRL0BUFF;
|
uint8_t * ctrl0buff = CTRL0BUFF;
|
||||||
|
|
||||||
// TODO: Check if needs to be do-while to re-check.
|
// TODO: Check if needs to be do-while to re-check.
|
||||||
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;
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf("[USB] TRANSFER, token = %02x, ep = %d, bmRequestType = %02x, bRequest = %02x\n", token, ep, pUSBFS_SetupReqPak->bmRequestType, pUSBFS_SetupReqPak->bRequest);
|
if( usb_debug ) printf("[USB] TRANSFER, token = %02x, ep = %d, bmRequestType = %02x, bRequest = %02x\n", token, ep, pUSBFS_SetupReqPak->bmRequestType, pUSBFS_SetupReqPak->bRequest);
|
||||||
|
#endif
|
||||||
switch ( token )
|
switch ( token )
|
||||||
{
|
{
|
||||||
case CUIS_TOKEN_IN:
|
case CUIS_TOKEN_IN:
|
||||||
if( ep )
|
if( ep )
|
||||||
{
|
{
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
#if FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
len = HandleInRequest( ctx, ep, ctx->ENDPOINTS[ ep ], 0 );
|
len = HandleInRequest( ctx, ep, ctx->endpoints[ep].in, 0 );
|
||||||
#endif
|
#endif
|
||||||
UEP_CTRL_TX(ep) ^= USBFS_UEP_T_TOG;
|
UEP_CTRL_TX(ep) ^= USBFS_UEP_T_TOG;
|
||||||
if( len )
|
if( len )
|
||||||
{
|
{
|
||||||
|
|
@ -99,7 +111,7 @@ void USBFS_IRQHandler()
|
||||||
{
|
{
|
||||||
UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK;
|
UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK;
|
||||||
}
|
}
|
||||||
ctx->USBFS_Endp_Busy[ ep ] = 0;
|
ctx->endpoints[ep].busy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -107,7 +119,7 @@ void USBFS_IRQHandler()
|
||||||
/* end-point 0 data in interrupt */
|
/* end-point 0 data in interrupt */
|
||||||
if( ctx->USBFS_SetupReqLen == 0 )
|
if( ctx->USBFS_SetupReqLen == 0 )
|
||||||
{
|
{
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
||||||
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES ) | UEP_R_RES_ACK;
|
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES ) | UEP_R_RES_ACK;
|
||||||
#else
|
#else
|
||||||
|
|
@ -142,7 +154,7 @@ void USBFS_IRQHandler()
|
||||||
UEP_CTRL_TX(0) ^= USBFS_UEP_T_TOG;
|
UEP_CTRL_TX(0) ^= USBFS_UEP_T_TOG;
|
||||||
ctx->USBFS_SetupReqLen -= len;
|
ctx->USBFS_SetupReqLen -= len;
|
||||||
ctx->pCtrlPayloadPtr += len;
|
ctx->pCtrlPayloadPtr += len;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
if( len && USBFSCTX.USBFS_SetupReqCode != HID_GET_REPORT )
|
if( len && USBFSCTX.USBFS_SetupReqCode != HID_GET_REPORT )
|
||||||
|
|
@ -231,7 +243,7 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) ^= USBFS_UEP_R_TOG;
|
UEP_CTRL_TX(0) ^= USBFS_UEP_R_TOG;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_RX(0) ^= USBFS_UEP_R_TOG;
|
UEP_CTRL_RX(0) ^= USBFS_UEP_R_TOG;
|
||||||
|
|
@ -241,13 +253,13 @@ void USBFS_IRQHandler()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x)|| defined (CH32V10x)
|
||||||
UEP_CTRL_TX(ep) ^= USBFS_UEP_R_TOG;
|
UEP_CTRL_TX(ep) ^= USBFS_UEP_R_TOG;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_RX(ep) ^= USBFS_UEP_R_TOG;
|
UEP_CTRL_RX(ep) ^= USBFS_UEP_R_TOG;
|
||||||
#endif
|
#endif
|
||||||
#if FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
HandleDataOut( ctx, ep, ctx->ENDPOINTS[ep], len );
|
HandleDataOut( ctx, ep, ctx->endpoints[ep].out, len );
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -255,11 +267,11 @@ void USBFS_IRQHandler()
|
||||||
|
|
||||||
/* Setup stage processing */
|
/* Setup stage processing */
|
||||||
case CUIS_TOKEN_SETUP:
|
case CUIS_TOKEN_SETUP:
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
#if !defined (CH32V10x)
|
#if !defined (CH32V10x)
|
||||||
if (!(USBFS->INT_ST & 0x80)) goto replycomplete;
|
if (!(USBFS->INT_ST & 0x80)) goto replycomplete;
|
||||||
#endif
|
#endif
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_T_TOG | USBFS_UEP_R_RES_NAK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_AUTO_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_T_TOG | USBFS_UEP_R_RES_NAK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_R_AUTO_TOG;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
||||||
UEP_CTRL_RX(0) = USBFS_UEP_R_RES_NAK | CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_TOG;
|
UEP_CTRL_RX(0) = USBFS_UEP_R_RES_NAK | CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_TOG;
|
||||||
|
|
@ -271,13 +283,15 @@ void USBFS_IRQHandler()
|
||||||
int USBFS_SetupReqLen = USBFSCTX.USBFS_SetupReqLen = pUSBFS_SetupReqPak->wLength;
|
int USBFS_SetupReqLen = USBFSCTX.USBFS_SetupReqLen = pUSBFS_SetupReqPak->wLength;
|
||||||
int USBFS_SetupReqIndex = pUSBFS_SetupReqPak->wIndex;
|
int USBFS_SetupReqIndex = pUSBFS_SetupReqPak->wIndex;
|
||||||
int USBFS_IndexValue = USBFSCTX.USBFS_IndexValue = ( pUSBFS_SetupReqPak->wIndex << 16 ) | pUSBFS_SetupReqPak->wValue;
|
int USBFS_IndexValue = USBFSCTX.USBFS_IndexValue = ( pUSBFS_SetupReqPak->wIndex << 16 ) | pUSBFS_SetupReqPak->wValue;
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf( "[USB] SETUP: %02x %02x %02d %02x %04x\n", USBFS_SetupReqType, USBFS_SetupReqCode, USBFS_SetupReqLen, USBFS_SetupReqIndex, USBFS_IndexValue );
|
if( usb_debug ) printf( "[USB] SETUP: %02x %02x %02d %02x %04x\n", USBFS_SetupReqType, USBFS_SetupReqCode, USBFS_SetupReqLen, USBFS_SetupReqIndex, USBFS_IndexValue );
|
||||||
|
#endif
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
||||||
{
|
{
|
||||||
#if FUSB_HID_INTERFACES > 0 || FUSB_USER_HANDLERS
|
#if FUSB_HID_INTERFACES > 0 || FUSB_USER_HANDLERS
|
||||||
if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS )
|
if( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS || ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_VENDOR )
|
||||||
{
|
{
|
||||||
/* Class Request */
|
/* Class Request */
|
||||||
switch( USBFS_SetupReqCode )
|
switch( USBFS_SetupReqCode )
|
||||||
|
|
@ -288,9 +302,12 @@ void USBFS_IRQHandler()
|
||||||
len = HandleHidUserSetReportSetup( ctx, pUSBFS_SetupReqPak );
|
len = HandleHidUserSetReportSetup( ctx, pUSBFS_SetupReqPak );
|
||||||
if( len < 0 ) goto sendstall;
|
if( len < 0 ) goto sendstall;
|
||||||
ctx->USBFS_SetupReqLen = len;
|
ctx->USBFS_SetupReqLen = len;
|
||||||
|
#else
|
||||||
|
ctx->USBFS_SetupReqLen = 0;
|
||||||
|
#endif
|
||||||
UEP_CTRL_LEN(0) = 0;
|
UEP_CTRL_LEN(0) = 0;
|
||||||
// Previously would have been a CTRL_RX = ACK && TOG, but not here on the 203.
|
// Previously would have been a CTRL_RX = ACK && TOG, but not here on the 203.
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG | CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
||||||
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ;
|
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ;
|
||||||
#else
|
#else
|
||||||
|
|
@ -298,10 +315,15 @@ void USBFS_IRQHandler()
|
||||||
UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_TOG;
|
||||||
#endif
|
#endif
|
||||||
goto replycomplete;
|
goto replycomplete;
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
case HID_GET_REPORT:
|
case HID_GET_REPORT:
|
||||||
len = HandleHidUserGetReportSetup( ctx, pUSBFS_SetupReqPak );
|
len = HandleHidUserGetReportSetup( ctx, pUSBFS_SetupReqPak );
|
||||||
if( len < 0 ) goto sendstall;
|
if( len < 0 ) goto sendstall;
|
||||||
|
if( len == 0 )
|
||||||
|
{
|
||||||
|
USBFS_SendNAK( 0, 1 );
|
||||||
|
goto replycomplete;
|
||||||
|
}
|
||||||
ctx->USBFS_SetupReqLen = len;
|
ctx->USBFS_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 )
|
||||||
|
|
@ -358,9 +380,12 @@ void USBFS_IRQHandler()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ctx->USBFS_SetupReqLen = len;
|
ctx->USBFS_SetupReqLen = len;
|
||||||
copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
if( ctx->pCtrlPayloadPtr )
|
||||||
// printf("%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", ctrl0buff[0], ctrl0buff[1], ctrl0buff[2], ctrl0buff[3], ctrl0buff[4], ctrl0buff[5], ctrl0buff[6]);
|
{
|
||||||
ctx->pCtrlPayloadPtr += len;
|
copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len );
|
||||||
|
// printf("%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", ctrl0buff[0], ctrl0buff[1], ctrl0buff[2], ctrl0buff[3], ctrl0buff[4], ctrl0buff[5], ctrl0buff[6]);
|
||||||
|
ctx->pCtrlPayloadPtr += len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ctx->USBFS_SetupReqType & DEF_UEP_IN || ctx->USBFS_SetupReqLen == 0)
|
if( ctx->USBFS_SetupReqType & DEF_UEP_IN || ctx->USBFS_SetupReqLen == 0)
|
||||||
|
|
@ -370,11 +395,11 @@ void USBFS_IRQHandler()
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_ACK;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG|USBFS_UEP_T_RES_ACK;
|
||||||
ctx->USBFS_SetupReqLen -= len;
|
ctx->USBFS_SetupReqLen -= len;
|
||||||
}
|
}
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else UEP_CTRL_TX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK;
|
else UEP_CTRL_TX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK;
|
||||||
#else
|
#else
|
||||||
else UEP_CTRL_RX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK;
|
else UEP_CTRL_RX(0)= USBFS_UEP_R_TOG|USBFS_UEP_R_RES_ACK;
|
||||||
#endif
|
#endif
|
||||||
// UEP_CTRL_LEN(0) = len;
|
// UEP_CTRL_LEN(0) = len;
|
||||||
// UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG;
|
// UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG;
|
||||||
// ctx->USBFS_SetupReqLen -= len;
|
// ctx->USBFS_SetupReqLen -= len;
|
||||||
|
|
@ -383,8 +408,8 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
goto sendstall;
|
goto sendstall;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -418,6 +443,13 @@ void USBFS_IRQHandler()
|
||||||
len = USBFS_SetupReqLen;
|
len = USBFS_SetupReqLen;
|
||||||
ctx->USBFS_SetupReqLen = len;
|
ctx->USBFS_SetupReqLen = len;
|
||||||
|
|
||||||
|
// Normally we would send data immediately
|
||||||
|
// but for sake of saving 20 bytes, we will send data on the next IN request.
|
||||||
|
// Leaving this code here in case that we found later that we NEED to send here.
|
||||||
|
// len = ctx->USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : ctx->USBFS_SetupReqLen;
|
||||||
|
// copyBuffer( ctrl0buff, ctx->pCtrlPayloadPtr, len ); // FYI -> Would need to do this if using DMA
|
||||||
|
// ctx->pCtrlPayloadPtr += len;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -438,6 +470,12 @@ void USBFS_IRQHandler()
|
||||||
case USB_SET_CONFIGURATION:
|
case USB_SET_CONFIGURATION:
|
||||||
ctx->USBFS_DevConfig = (uint8_t)( ctx->USBFS_IndexValue & 0xFF );
|
ctx->USBFS_DevConfig = (uint8_t)( ctx->USBFS_IndexValue & 0xFF );
|
||||||
ctx->USBFS_DevEnumStatus = 0x01;
|
ctx->USBFS_DevEnumStatus = 0x01;
|
||||||
|
for( int ep = 1; ep < FUSB_MAX_EP_CNT; ep++ )
|
||||||
|
{
|
||||||
|
// reset all DATAx
|
||||||
|
UEP_CTRL_RX(ep) &= ~USBFS_UEP_R_TOG;
|
||||||
|
UEP_CTRL_TX(ep) &= ~USBFS_UEP_T_TOG;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Clear or disable one usb feature */
|
/* Clear or disable one usb feature */
|
||||||
|
|
@ -463,14 +501,14 @@ void USBFS_IRQHandler()
|
||||||
if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
||||||
{
|
{
|
||||||
/* Clear End-point Feature */
|
/* Clear End-point Feature */
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
// UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_STALL | CHECK_USBFS_UEP_T_AUTO_TOG;
|
// UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_STALL | CHECK_USBFS_UEP_T_AUTO_TOG;
|
||||||
if( USBFS_SetupReqIndex & DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_NAK;
|
if( USBFS_SetupReqIndex & DEF_UEP_IN && (ctx->endpoints[ep].mode & USBFS_EP_MODE_TX) ) UEP_CTRL_TX(ep) = USBFS_UEP_T_RES_NAK;
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_TX(ep) = USBFS_UEP_R_RES_ACK;
|
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) ) UEP_CTRL_TX(ep) = USBFS_UEP_R_RES_ACK;
|
||||||
#else
|
#else
|
||||||
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_RX(ep) = USBFS_UEP_R_RES_ACK;
|
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) ) UEP_CTRL_RX(ep) = USBFS_UEP_R_RES_ACK;
|
||||||
#endif
|
#endif
|
||||||
else goto sendstall;
|
else goto sendstall;
|
||||||
}
|
}
|
||||||
|
|
@ -512,13 +550,13 @@ void USBFS_IRQHandler()
|
||||||
/* Set Endpoint Feature */
|
/* Set Endpoint Feature */
|
||||||
if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
if( (uint8_t)( USBFS_IndexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
||||||
{
|
{
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
if( (USBFS_SetupReqIndex & DEF_UEP_IN) && ctx->endpoint_mode[ep] == -1 )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_STALL;
|
if( (USBFS_SetupReqIndex & DEF_UEP_IN) && (ctx->endpoints[ep].mode & USBFS_EP_MODE_TX) )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_STALL;
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && ctx->endpoint_mode[ep] == 1 )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL;
|
else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) )UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL;
|
||||||
#else
|
#else
|
||||||
else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && ctx->endpoint_mode[ep] == 1 )UEP_CTRL_RX(ep) = ( UEP_CTRL_RX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL;
|
else if( (USBFS_SetupReqIndex & DEF_UEP_OUT) && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) )UEP_CTRL_RX(ep) = ( UEP_CTRL_RX(ep) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_STALL;
|
||||||
#endif
|
#endif
|
||||||
else goto sendstall;
|
else goto sendstall;
|
||||||
}
|
}
|
||||||
|
|
@ -553,13 +591,13 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
else if( ( USBFS_SetupReqType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
||||||
{
|
{
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
if( USBFS_SetupReqIndex & DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_T_RES_MASK ) == USBFS_UEP_T_RES_STALL;
|
if( USBFS_SetupReqIndex & DEF_UEP_IN && (ctx->endpoints[ep].mode & USBFS_EP_MODE_TX) ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_T_RES_MASK ) == USBFS_UEP_T_RES_STALL;
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL;
|
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL;
|
||||||
#else
|
#else
|
||||||
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL;
|
else if( USBFS_SetupReqIndex & DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBFS_EP_MODE_RX) ) ctrl0buff[0] = ( UEP_CTRL_RX(ep) & USBFS_UEP_R_RES_MASK ) == USBFS_UEP_R_RES_STALL;
|
||||||
#endif
|
#endif
|
||||||
else goto sendstall;
|
else goto sendstall;
|
||||||
}
|
}
|
||||||
|
|
@ -584,10 +622,18 @@ void USBFS_IRQHandler()
|
||||||
if( USBFS_SetupReqType & DEF_UEP_IN )
|
if( USBFS_SetupReqType & DEF_UEP_IN )
|
||||||
{
|
{
|
||||||
len = ( USBFS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen;
|
len = ( USBFS_SetupReqLen > DEF_USBD_UEP0_SIZE )? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen;
|
||||||
USBFS_SetupReqLen -= len;
|
|
||||||
UEP_CTRL_LEN(0) = len;
|
UEP_CTRL_LEN(0) = len;
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_ACK;
|
|
||||||
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK;
|
if (USBFS_SetupReqCode != USB_GET_DESCRIPTOR)
|
||||||
|
{
|
||||||
|
ctx->USBFS_SetupReqLen -= len;
|
||||||
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UEP_CTRL_LEN(0) = 0;
|
||||||
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_ACK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -599,8 +645,8 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) = CHECK_USBFS_UEP_T_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
||||||
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ;
|
// R8_UEP0_CTRL = (R8_UEP0_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK ;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_RX(0) = CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
UEP_CTRL_RX(0) = CHECK_USBFS_UEP_R_AUTO_TOG | USBFS_UEP_R_RES_ACK | USBFS_UEP_R_TOG;
|
||||||
|
|
@ -614,7 +660,7 @@ void USBFS_IRQHandler()
|
||||||
// control flow to hard-abort here.
|
// control flow to hard-abort here.
|
||||||
sendstall:
|
sendstall:
|
||||||
// if one request not support, return stall. Stall means permanent error.
|
// if one request not support, return stall. Stall means permanent error.
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL | USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL | USBFS_UEP_R_TOG | USBFS_UEP_R_RES_STALL;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_STALL;
|
||||||
|
|
@ -635,7 +681,9 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else if( intfgst & CRB_UIF_BUS_RST )
|
else if( intfgst & CRB_UIF_BUS_RST )
|
||||||
{
|
{
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf("[USB] RESET\n");
|
if( usb_debug ) printf("[USB] RESET\n");
|
||||||
|
#endif
|
||||||
/* usb reset interrupt processing */
|
/* usb reset interrupt processing */
|
||||||
ctx->USBFS_DevConfig = 0;
|
ctx->USBFS_DevConfig = 0;
|
||||||
ctx->USBFS_DevAddr = 0;
|
ctx->USBFS_DevAddr = 0;
|
||||||
|
|
@ -648,7 +696,9 @@ void USBFS_IRQHandler()
|
||||||
}
|
}
|
||||||
else if( intfgst & CRB_UIF_SUSPEND )
|
else if( intfgst & CRB_UIF_SUSPEND )
|
||||||
{
|
{
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf("[USB] SUSPEND\n");
|
if( usb_debug ) printf("[USB] SUSPEND\n");
|
||||||
|
#endif
|
||||||
USBFS->INT_FG = USBFS_UMS_SUSPEND;
|
USBFS->INT_FG = USBFS_UMS_SUSPEND;
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
/* usb suspend interrupt processing */
|
/* usb suspend interrupt processing */
|
||||||
|
|
@ -671,7 +721,9 @@ void USBFS_IRQHandler()
|
||||||
{
|
{
|
||||||
/* other interrupts */
|
/* other interrupts */
|
||||||
USBFS->INT_FG = intfgst & 0xff;
|
USBFS->INT_FG = intfgst & 0xff;
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug) printf("[USB] intfgst = %04x\n",intfgst);
|
if( usb_debug) printf("[USB] intfgst = %04x\n",intfgst);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FUSB_IO_PROFILE
|
#if FUSB_IO_PROFILE
|
||||||
|
|
@ -683,124 +735,132 @@ void USBFS_IRQHandler()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBFS_InternalFinishSetup()
|
WEAK void USBFS_InternalFinishSetup()
|
||||||
{
|
{
|
||||||
|
USBFS->UEP4_1_MOD = 0;
|
||||||
|
USBFS->UEP2_3_MOD = 0;
|
||||||
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
|
USBFS->UEP567_MOD = 0;
|
||||||
|
#else
|
||||||
|
USBFS->UEP5_6_MOD = 0;
|
||||||
|
USBFS->UEP7_MOD = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for( int i = 0; i < FUSB_BUFFERS_NUMBER; i++ )
|
||||||
|
{
|
||||||
|
UEP_CTRL_LEN(i) = 0;
|
||||||
|
memset(USBFSCTX.ep_buffers[i], 0, 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffer_counter = 1;
|
||||||
|
|
||||||
|
USBFSCTX.endpoints[0].mode = USBFS_EP_MODE_RX | USBFS_EP_MODE_TX;
|
||||||
|
|
||||||
#if FUSB_EP1_MODE
|
#if FUSB_EP1_MODE
|
||||||
USBFSCTX.endpoint_mode[1] = FUSB_EP1_MODE;
|
USBFSCTX.endpoints[1].mode = FUSB_EP1_MODE;
|
||||||
#if FUSB_EP1_MODE > 0
|
USBFS->UEP4_1_MOD |= FUSB_EP1_MODE << 4;
|
||||||
USBFS->UEP4_1_MOD = USBFS_UEP1_TX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP4_1_MOD = USBFS_UEP1_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if FUSB_EP4_MODE
|
|
||||||
USBFSCTX.endpoint_mode[4] = FUSB_EP4_MODE;
|
|
||||||
#if FUSB_EP4_MODE > 0
|
|
||||||
USBFS->UEP4_1_MOD |= USBFS_UEP4_TX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP4_1_MOD |= USBFS_UEP4_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP2_MODE
|
#if FUSB_EP2_MODE
|
||||||
USBFSCTX.endpoint_mode[2] = FUSB_EP2_MODE;
|
USBFSCTX.endpoints[2].mode = FUSB_EP2_MODE;
|
||||||
#if FUSB_EP2_MODE > 0
|
USBFS->UEP2_3_MOD |= FUSB_EP2_MODE;
|
||||||
USBFS->UEP2_3_MOD = USBFS_UEP2_TX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP2_3_MOD = USBFS_UEP2_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP3_MODE
|
#if FUSB_EP3_MODE
|
||||||
USBFSCTX.endpoint_mode[3] = FUSB_EP3_MODE;
|
USBFSCTX.endpoints[3].mode = FUSB_EP3_MODE;
|
||||||
#if FUSB_EP3_MODE > 0
|
USBFS->UEP2_3_MOD |= FUSB_EP3_MODE << 4;
|
||||||
USBFS->UEP2_3_MOD |= USBFS_UEP3_TX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP2_3_MOD |= USBFS_UEP3_RX_EN;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP4_MODE
|
||||||
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
|
USBFSCTX.endpoints[4].mode = FUSB_EP4_MODE &0xc;
|
||||||
|
|
||||||
|
USBFSCTX.endpoints[4].out = ((USBFSCTX.endpoints[4].mode & USBFS_EP_MODE_RX)?((uintptr_t)USBFSCTX.ep_buffers[buffer_counter]):0);
|
||||||
|
USBFSCTX.endpoints[4].in = ((USBFSCTX.endpoints[4].mode & USBFS_EP_MODE_TX)?((uintptr_t)USBFSCTX.ep_buffers[buffer_counter+64]):0);
|
||||||
|
buffer_counter += (((USBFSCTX.endpoints[4].mode & USBFS_EP_MODE_TX)?1:0) + ((USBFSCTX.endpoints[4].mode & USBFS_EP_MODE_RX)?1:0));
|
||||||
|
#else
|
||||||
|
USBFSCTX.endpoints[4].mode = FUSB_EP4_MODE;
|
||||||
|
#endif
|
||||||
|
USBFS->UEP4_1_MOD |= USBFSCTX.endpoints[4].mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP5_MODE
|
#if FUSB_EP5_MODE
|
||||||
USBFSCTX.endpoint_mode[5] = FUSB_EP5_MODE;
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
#if FUSB_EP5_MODE > 0
|
USBFSCTX.endpoints[5].mode = FUSB_EP5_MODE & 0xc;
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
USBFS->UEP567_MOD |= (FUSB_EP5_MODE & 0xc) >> 2;
|
||||||
USBFS->UEP567_MOD = USBFS_UEP5_TX_EN;
|
|
||||||
#else
|
#else
|
||||||
USBFS->UEP5_6_MOD = USBFS_UEP5_TX_EN;
|
USBFSCTX.endpoints[5].mode = FUSB_EP5_MODE;
|
||||||
#endif
|
USBFS->UEP5_6_MOD |= FUSB_EP5_MODE;
|
||||||
#else
|
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
|
||||||
USBFS->UEP567_MOD = USBFS_UEP5_RX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP5_6_MOD = USBFS_UEP5_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP6_MODE
|
#if FUSB_EP6_MODE
|
||||||
USBFSCTX.endpoint_mode[6] = FUSB_EP6_MODE;
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
#if FUSB_EP6_MODE > 0
|
USBFSCTX.endpoints[6].mode = FUSB_EP6_MODE & 0xc;
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
USBFS->UEP567_MOD |= FUSB_EP6_MODE & 0xc;
|
||||||
USBFS->UEP567_MOD = USBFS_UEP6_TX_EN;
|
|
||||||
#else
|
#else
|
||||||
USBFS->UEP5_6_MOD |= USBFS_UEP6_TX_EN;
|
USBFSCTX.endpoints[6].mode = FUSB_EP6_MODE;
|
||||||
#endif
|
USBFS->UEP5_6_MOD |= (FUSB_EP6_MODE & 0xc) << 4;
|
||||||
#else
|
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
|
||||||
USBFS->UEP567_MOD |= USBFS_UEP6_RX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP5_6_MOD |= USBFS_UEP6_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP7_MODE
|
#if FUSB_EP7_MODE
|
||||||
USBFSCTX.endpoint_mode[7] = FUSB_EP7_MODE;
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
#if FUSB_EP7_MODE > 0
|
USBFSCTX.endpoints[7].mode = FUSB_EP7_MODE & 0xc;
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
USBFS->UEP567_MOD |= (FUSB_EP7_MODE & 0xc) << 2;
|
||||||
USBFS->UEP567_MOD |= USBFS_UEP7_TX_EN;
|
|
||||||
#else
|
#else
|
||||||
USBFS->UEP7_MOD = USBFS_UEP1_TX_EN;
|
USBFSCTX.endpoints[7].mode = FUSB_EP7_MODE;
|
||||||
#endif
|
USBFS->UEP7_MOD = FUSB_EP7_MODE;
|
||||||
#else
|
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
|
||||||
USBFS->UEP567_MOD |= USBFS_UEP7_RX_EN;
|
|
||||||
#else
|
|
||||||
USBFS->UEP7_MOD = USBFS_UEP1_RX_EN;
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined (FUSB_CONFIG_EPS) || !FUSB_CONFIG_EPS
|
UEP_DMA(0) = (uintptr_t)USBFSCTX.ep_buffers[0];
|
||||||
#error You must have at least EP0!
|
USBFSCTX.endpoints[0].in = USBFSCTX.ep_buffers[0];
|
||||||
#endif
|
USBFSCTX.endpoints[0].out = USBFSCTX.ep_buffers[0];
|
||||||
|
|
||||||
for( int i = 0; i < FUSB_CONFIG_EPS; i++ )
|
for( int i = 1; i < FUSB_MAX_EP_CNT; i++ )
|
||||||
{
|
{
|
||||||
UEP_DMA(i) = (uintptr_t)USBFSCTX.ENDPOINTS[i];
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
|
if( i == 4 ) continue;
|
||||||
|
#endif
|
||||||
|
if( buffer_counter >= FUSB_BUFFERS_NUMBER ) break;
|
||||||
|
if( USBFSCTX.endpoints[i].mode )
|
||||||
|
{
|
||||||
|
int tx_buf = ((USBFSCTX.endpoints[i].mode & USBFS_EP_MODE_TX)?1:0) + (USBFSCTX.endpoints[i].mode & 1);
|
||||||
|
int rx_buf = ((USBFSCTX.endpoints[i].mode & USBFS_EP_MODE_RX)?1:0) + (USBFSCTX.endpoints[i].mode & 1);
|
||||||
|
|
||||||
|
UEP_DMA(i) = (uintptr_t)USBFSCTX.ep_buffers[buffer_counter];
|
||||||
|
if( rx_buf ) USBFSCTX.endpoints[i].out = (uint8_t *)USBFSCTX.ep_buffers[buffer_counter];
|
||||||
|
if( tx_buf ) USBFSCTX.endpoints[i].in = (uint8_t *)USBFSCTX.ep_buffers[buffer_counter+rx_buf];
|
||||||
|
|
||||||
|
buffer_counter += (tx_buf + rx_buf);
|
||||||
|
// printf("EP%d mode = %d, out buffer = 0x%08x, in buffer = 0x%08x, DMA = %08x\n", i, USBFSCTX.endpoints[i].mode, USBFSCTX.endpoints[i].out, USBFSCTX.endpoints[i].in, UEP_DMA(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_T_AUTO_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_T_AUTO_TOG;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG;
|
UEP_CTRL_TX(0) = USBFS_UEP_T_RES_NAK | CHECK_USBFS_UEP_T_AUTO_TOG;
|
||||||
UEP_CTRL_RX(0) = USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_R_AUTO_TOG;
|
UEP_CTRL_RX(0) = USBFS_UEP_R_RES_ACK | CHECK_USBFS_UEP_R_AUTO_TOG;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for( int i = 1; i < FUSB_CONFIG_EPS; i++ )
|
for( int i = 1; i < FUSB_MAX_EP_CNT; i++ )
|
||||||
{
|
{
|
||||||
if( USBFSCTX.endpoint_mode[i] > 0 )
|
if( USBFSCTX.endpoints[i].mode & USBFS_EP_MODE_TX )
|
||||||
{
|
{
|
||||||
UEP_CTRL_TX(i) = USBFS_UEP_T_RES_NAK;
|
UEP_CTRL_TX(i) = USBFS_UEP_T_RES_NAK;
|
||||||
}
|
}
|
||||||
else if( USBFSCTX.endpoint_mode[i] < 0 )
|
|
||||||
|
if( USBFSCTX.endpoints[i].mode & USBFS_EP_MODE_RX )
|
||||||
{
|
{
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
UEP_CTRL_TX(i) = USBFS_UEP_R_RES_ACK;
|
UEP_CTRL_TX(i) = USBFS_UEP_R_RES_ACK;
|
||||||
#else
|
#else
|
||||||
UEP_CTRL_RX(i) = USBFS_UEP_R_RES_ACK;
|
UEP_CTRL_RX(i) = USBFS_UEP_R_RES_ACK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
USBFSCTX.USBFS_Endp_Busy[i] = 0;
|
USBFSCTX.endpoints[i].busy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -820,9 +880,19 @@ int USBFSSetup()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (CH32V20x) || defined (CH32V30x) || defined(CH32L103)
|
#if defined (CH32V20x) || defined (CH32V30x) || defined(CH32L103)
|
||||||
#ifdef CH32V30x_D8C
|
#if defined(CH32V30x_D8C)
|
||||||
RCC->CFGR2 = RCC_USBHSSRC | RCC_USBHSPLL | 1<< RCC_USBHSCLK_OFFSET | RCC_USBHSPLLSRC | 1 << RCC_USBHSDIV_OFFSET;
|
RCC->CFGR2 = RCC_USBHSSRC | RCC_USBHSPLL | 1<< RCC_USBHSCLK_OFFSET | RCC_USBHSPLLSRC | 1 << RCC_USBHSDIV_OFFSET;
|
||||||
RCC->AHBPCENR |= RCC_USBHSEN;
|
RCC->AHBPCENR |= RCC_USBHSEN;
|
||||||
|
#elif defined(CH32L103)
|
||||||
|
#if FUNCONF_SYSTEM_CORE_CLOCK == 96000000
|
||||||
|
RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22)) | (1<<22);
|
||||||
|
#elif FUNCONF_SYSTEM_CORE_CLOCK == 72000000
|
||||||
|
RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22)) | (2<<22);
|
||||||
|
#elif FUNCONF_SYSTEM_CORE_CLOCK == 48000000
|
||||||
|
RCC->CFGR0 = (RCC->CFGR0 & ~(3<<22));
|
||||||
|
#else
|
||||||
|
#error CH32L103 needs 96/72/48MHz main clock for USB to work
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
// USBPRE[1:0] = 10: Divided by 3 (when PLLCLK=144MHz);
|
// USBPRE[1:0] = 10: Divided by 3 (when PLLCLK=144MHz);
|
||||||
// Must be done before enabling clock to USBFS tree.
|
// Must be done before enabling clock to USBFS tree.
|
||||||
|
|
@ -842,11 +912,11 @@ int USBFSSetup()
|
||||||
|
|
||||||
#if defined (CH32X03x)
|
#if defined (CH32X03x)
|
||||||
RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC;
|
RCC->APB2PCENR |= RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC;
|
||||||
// #ifdef FUSB_VDD_5V
|
#if FUSB_VDD_5V
|
||||||
// AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK | USB_PHY_V33)) | UDP_PUE_10K | USB_IOEN;
|
AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK | USB_PHY_V33)) | UDP_PUE_10K | USB_IOEN;
|
||||||
// #else
|
#else
|
||||||
AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK )) | USB_PHY_V33 | UDP_PUE_1K5 | USB_IOEN;
|
AFIO->CTLR = (AFIO->CTLR & ~(UDP_PUE_MASK | UDM_PUE_MASK )) | USB_PHY_V33 | UDP_PUE_1K5 | USB_IOEN;
|
||||||
// #endif
|
#endif
|
||||||
// Enable PC16/17 Alternate Function (USB)
|
// Enable PC16/17 Alternate Function (USB)
|
||||||
// According to EVT, GPIO16 = GPIO_Mode_IN_FLOATING, GPIO17 = GPIO_Mode_IPU
|
// According to EVT, GPIO16 = GPIO_Mode_IN_FLOATING, GPIO17 = GPIO_Mode_IPU
|
||||||
GPIOC->CFGXR = ( GPIOC->CFGXR & ~( (0xf<<(4*0)) | (0xf<<(4*1)) ) ) |
|
GPIOC->CFGXR = ( GPIOC->CFGXR & ~( (0xf<<(4*0)) | (0xf<<(4*1)) ) ) |
|
||||||
|
|
@ -888,7 +958,7 @@ int USBFSSetup()
|
||||||
USBFS->BASE_CTRL = USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN | USBFS_UC_DEV_PU_EN;
|
USBFS->BASE_CTRL = USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN | USBFS_UC_DEV_PU_EN;
|
||||||
USBFS->INT_FG = 0xff;
|
USBFS->INT_FG = 0xff;
|
||||||
USBFS_InternalFinishSetup();
|
USBFS_InternalFinishSetup();
|
||||||
USBFS->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN;
|
USBFS->UDEV_CTRL = USBFS_UD_PORT_EN; // Previously here also was USBFS_UD_PD_DIS, but cnlohr encountered instabilities with it on ch570
|
||||||
|
|
||||||
NVIC_EnableIRQ( USB_IRQn );
|
NVIC_EnableIRQ( USB_IRQn );
|
||||||
|
|
||||||
|
|
@ -923,38 +993,43 @@ void USBFSReset()
|
||||||
USBFS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
|
USBFS->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL;
|
||||||
USBFS->BASE_CTRL = 0x00;
|
USBFS->BASE_CTRL = 0x00;
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void USBFSReset()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp )
|
uint8_t * USBFS_GetEPBufferIfAvailable( int endp )
|
||||||
{
|
{
|
||||||
if( USBFSCTX.USBFS_Endp_Busy[ endp ] ) return 0;
|
if( USBFSCTX.endpoints[endp].busy ) return 0;
|
||||||
return USBFSCTX.ENDPOINTS[ endp ];
|
return USBFSCTX.endpoints[ endp ].in;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int USBFS_SendEndpoint( int endp, int len )
|
int USBFS_SendEndpoint( int endp, int len )
|
||||||
{
|
{
|
||||||
if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.USBFS_Endp_Busy[ endp ] ) return -1;
|
if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.endpoints[endp].busy ) return -1;
|
||||||
// This prevents sending while ep0 is receiving
|
// This prevents sending while ep0 is receiving
|
||||||
if( USBFSCTX.USBFS_SetupReqLen > 0 ) return -2;
|
if( USBFSCTX.USBFS_SetupReqLen > 0 ) return -2;
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
// Check RB_UIS_SETUP_ACT
|
// Check RB_UIS_SETUP_ACT
|
||||||
if( (USBFS->INT_ST & 0x80) ) return -3;
|
if( (USBFS->INT_ST & 0x80) ) return -3;
|
||||||
#endif
|
#endif
|
||||||
NVIC_DisableIRQ( USB_IRQn );
|
NVIC_DisableIRQ( USB_IRQn );
|
||||||
UEP_CTRL_LEN( endp ) = len;
|
UEP_CTRL_LEN( endp ) = len;
|
||||||
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
||||||
USBFSCTX.USBFS_Endp_Busy[ endp ] = 1;
|
USBFSCTX.endpoints[endp].busy = 1;
|
||||||
NVIC_EnableIRQ( USB_IRQn );
|
NVIC_EnableIRQ( USB_IRQn );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy)
|
int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy)
|
||||||
{
|
{
|
||||||
if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.USBFS_Endp_Busy[ endp ] ) return -1;
|
if( USBFSCTX.USBFS_errata_dont_send_endpoint_in_window || USBFSCTX.endpoints[endp].busy ) return -1;
|
||||||
// This prevents sending while ep0 is receiving
|
// This prevents sending while ep0 is receiving
|
||||||
if( USBFSCTX.USBFS_SetupReqLen > 0 ) return USBFSCTX.USBFS_SetupReqLen;
|
if( USBFSCTX.USBFS_SetupReqLen > 0 ) return USBFSCTX.USBFS_SetupReqLen;
|
||||||
#if defined (CH5xx) || defined (CH32X03x)
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
// Check RB_UIS_SETUP_ACT
|
// Check RB_UIS_SETUP_ACT
|
||||||
if( (USBFS->INT_ST & 0x80) ) return -3;
|
if( (USBFS->INT_ST & 0x80) ) return -3;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -962,24 +1037,36 @@ int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy)
|
||||||
{
|
{
|
||||||
if( copy )
|
if( copy )
|
||||||
{
|
{
|
||||||
UEP_DMA( endp ) = (uintptr_t)USBFSCTX.ENDPOINTS[endp];
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
copyBuffer( USBFSCTX.ENDPOINTS[endp], data, len );
|
if ( endp != 4 ) UEP_DMA( endp ) = (uintptr_t)USBFSCTX.ep_buffers[endp];
|
||||||
|
#else
|
||||||
|
UEP_DMA( endp ) = (uintptr_t)USBFSCTX.ep_buffers[endp];
|
||||||
|
#endif
|
||||||
|
copyBuffer( USBFSCTX.endpoints[endp].in, data, len );
|
||||||
copyBufferComplete();
|
copyBufferComplete();
|
||||||
}
|
}
|
||||||
else UEP_DMA( endp ) = (uintptr_t)data;
|
else
|
||||||
|
{
|
||||||
|
// EP in bi-directional mode won't work with direct DMA
|
||||||
|
#if defined(CH5xx) || defined(CH32X03x)
|
||||||
|
if ( endp != 4 ) UEP_DMA( endp ) = (uintptr_t)data;
|
||||||
|
#else
|
||||||
|
UEP_DMA( endp ) = (uintptr_t)data;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// NVIC_DisableIRQ( USB_IRQn );
|
// NVIC_DisableIRQ( USB_IRQn );
|
||||||
UEP_CTRL_LEN( endp ) = len;
|
UEP_CTRL_LEN( endp ) = len;
|
||||||
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
||||||
USBFSCTX.USBFS_Endp_Busy[ endp ] = 1;
|
USBFSCTX.endpoints[endp].busy = 1;
|
||||||
// NVIC_EnableIRQ( USB_IRQn );
|
// NVIC_EnableIRQ( USB_IRQn );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int USBFS_SendACK( int endp, int tx )
|
int USBFS_SendACK( int endp, int tx )
|
||||||
{
|
{
|
||||||
if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_ACK;
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK;
|
else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK;
|
||||||
#else
|
#else
|
||||||
else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK;
|
else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_ACK;
|
||||||
|
|
@ -987,10 +1074,10 @@ static inline int USBFS_SendACK( int endp, int tx )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int USBFS_SendNAK( int endp, int tx )
|
int USBFS_SendNAK( int endp, int tx )
|
||||||
{
|
{
|
||||||
if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK;
|
if( tx ) UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBFS_UEP_T_RES_MASK ) | USBFS_UEP_T_RES_NAK;
|
||||||
#if defined (CH5xx) || defined (CH32X03x) || defined (CH32V10x)
|
#if defined(CH5xx) || defined(CH32X03x) || defined (CH32V10x)
|
||||||
else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK;
|
else UEP_CTRL_TX(endp) = ( UEP_CTRL_TX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK;
|
||||||
#else
|
#else
|
||||||
else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK;
|
else UEP_CTRL_RX(endp) = ( UEP_CTRL_RX(endp) & ~USBFS_UEP_R_RES_MASK ) | USBFS_UEP_R_RES_NAK;
|
||||||
|
|
@ -999,20 +1086,46 @@ static inline int USBFS_SendNAK( int endp, int tx )
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF
|
#if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF
|
||||||
int HandleInRequest( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
__attribute__((weak)) int HandleInRequest( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleDataOut( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
// static uint8_t usb_inputbuffer[USBFS_PACKET_SIZE]; // this can be extended if polling rate is low
|
||||||
|
// static int usb_inbuf_idx;
|
||||||
|
WEAK void HandleDataOut( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
||||||
{
|
{
|
||||||
if ( endp == 0 )
|
if ( endp == 0 )
|
||||||
{
|
{
|
||||||
ctx->USBFS_SetupReqLen = 0; // To ACK
|
ctx->USBFS_SetupReqLen = 0; // To ACK
|
||||||
}
|
}
|
||||||
|
else if( endp == 2 )
|
||||||
|
{
|
||||||
|
// discard oldest if polling is too slow
|
||||||
|
int headroom = (sizeof(usb_inputbuffer) - usb_inbuf_idx) - len;
|
||||||
|
if(headroom < 0) {
|
||||||
|
// not enough space left, free up some
|
||||||
|
int offset = -headroom;
|
||||||
|
for(int i = offset; i < sizeof(usb_inputbuffer); i++) {
|
||||||
|
usb_inputbuffer[i -offset] = usb_inputbuffer[i];
|
||||||
|
}
|
||||||
|
usb_inbuf_idx -= offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < len; i++) {
|
||||||
|
usb_inputbuffer[usb_inbuf_idx++] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int HandleSetupCustom( struct _USBState *ctx, int setup_code )
|
void poll_input() {
|
||||||
|
if(usb_inbuf_idx) {
|
||||||
|
HandleUSBInput(usb_inbuf_idx, usb_inputbuffer);
|
||||||
|
usb_inbuf_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WEAK int HandleSetupCustom( struct _USBState *ctx, int setup_code )
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
if ( ctx->USBFS_SetupReqType & USB_REQ_TYP_CLASS )
|
if ( ctx->USBFS_SetupReqType & USB_REQ_TYP_CLASS )
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ typedef struct
|
||||||
__IO uint8_t MIS_ST;
|
__IO uint8_t MIS_ST;
|
||||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||||
__IO uint8_t INT_ST;
|
__IO uint8_t INT_ST;
|
||||||
__IO uint8_t RX_LEN;
|
__IO uint8_t RX_LEN;
|
||||||
__IO uint8_t Reserved0;
|
__IO uint8_t Reserved0;
|
||||||
__IO uint16_t Reserved1;
|
__IO uint16_t Reserved1;
|
||||||
__IO uint8_t UEP4_1_MOD;
|
__IO uint8_t UEP4_1_MOD;
|
||||||
__IO uint8_t UEP2_3_MOD;
|
__IO uint8_t UEP2_3_MOD;
|
||||||
__IO uint8_t UEP567_MOD;
|
__IO uint8_t UEP567_MOD;
|
||||||
|
|
@ -44,61 +44,66 @@ typedef struct
|
||||||
__IO uint16_t Reserved5;
|
__IO uint16_t Reserved5;
|
||||||
__IO uint16_t UEP3_DMA;
|
__IO uint16_t UEP3_DMA;
|
||||||
__IO uint16_t Reserved6;
|
__IO uint16_t Reserved6;
|
||||||
__IO uint8_t UEP0_TX_LEN;
|
__IO uint8_t UEP0_TX_LEN;
|
||||||
__IO uint8_t Reserved7;
|
__IO uint8_t Reserved7;
|
||||||
__IO uint8_t UEP0_TX_CTRL;
|
__IO uint8_t UEP0_TX_CTRL;
|
||||||
__IO uint8_t Reserved8;
|
__IO uint8_t Reserved8;
|
||||||
__IO uint8_t UEP1_TX_LEN;
|
__IO uint8_t UEP1_TX_LEN;
|
||||||
__IO uint8_t Reserved9;
|
__IO uint8_t Reserved9;
|
||||||
__IO uint8_t UEP1_TX_CTRL;
|
__IO uint8_t UEP1_TX_CTRL;
|
||||||
__IO uint8_t Reserved10;
|
__IO uint8_t Reserved10;
|
||||||
__IO uint8_t UEP2_TX_LEN;
|
__IO uint8_t UEP2_TX_LEN;
|
||||||
__IO uint8_t Reserved11;
|
__IO uint8_t Reserved11;
|
||||||
__IO uint8_t UEP2_TX_CTRL;
|
__IO uint8_t UEP2_TX_CTRL;
|
||||||
__IO uint8_t Reserved12;
|
__IO uint8_t Reserved12;
|
||||||
__IO uint8_t UEP3_TX_LEN;
|
__IO uint8_t UEP3_TX_LEN;
|
||||||
__IO uint8_t Reserved13;
|
__IO uint8_t Reserved13;
|
||||||
__IO uint8_t UEP3_TX_CTRL;
|
__IO uint8_t UEP3_TX_CTRL;
|
||||||
__IO uint8_t Reserved14;
|
__IO uint8_t Reserved14;
|
||||||
__IO uint8_t UEP4_TX_LEN;
|
__IO uint8_t UEP4_TX_LEN;
|
||||||
__IO uint8_t Reserved15;
|
__IO uint8_t Reserved15;
|
||||||
__IO uint8_t UEP4_TX_CTRL;
|
__IO uint8_t UEP4_TX_CTRL;
|
||||||
__IO uint8_t Reserved16;
|
__IO uint8_t Reserved16;
|
||||||
__IO uint32_t Reserved17;
|
__IO uint32_t Reserved17;
|
||||||
__IO uint32_t Reserved18;
|
__IO uint32_t Reserved18;
|
||||||
__IO uint32_t Reserved19;
|
__IO uint32_t Reserved19;
|
||||||
__IO uint32_t Reserved20;
|
__IO uint32_t EP_JMPR; // Nothing here, but used for UEP 5,6,7 jump in UEP_(n) macros
|
||||||
__IO uint32_t Reserved21;
|
__IO uint32_t Reserved21;
|
||||||
__IO uint32_t Reserved22;
|
__IO uint32_t Reserved22;
|
||||||
__IO uint32_t Reserved23;
|
__IO uint32_t Reserved23;
|
||||||
__IO uint32_t Reserved24;
|
__IO uint32_t Reserved24; // 0x50
|
||||||
__IO uint16_t UEP5_DMA;
|
__IO uint16_t UEP5_DMA; // 0x54
|
||||||
__IO uint16_t UEP6_DMA;
|
__IO uint16_t Reserved25; // 0x56
|
||||||
__IO uint16_t UEP7_DMA;
|
__IO uint16_t UEP6_DMA; // 0x58
|
||||||
__IO uint32_t Reserved25;
|
__IO uint16_t Reserved26; // 0x5A
|
||||||
__IO uint8_t UEP5_TX_LEN;
|
__IO uint16_t UEP7_DMA; // 0x5C
|
||||||
__IO uint8_t Reserved26;
|
__IO uint16_t Reserved27; // 0x5E
|
||||||
__IO uint8_t UEP5_TX_CTRL;
|
__IO uint32_t Reserved28; // 0x60
|
||||||
__IO uint8_t Reserved27;
|
__IO uint8_t UEP5_TX_LEN; // 0x64
|
||||||
__IO uint8_t UEP6_TX_LEN;
|
__IO uint8_t Reserved29; // 0x65
|
||||||
__IO uint8_t Reserved28;
|
__IO uint8_t UEP5_TX_CTRL; // 0x66
|
||||||
__IO uint8_t UEP6_TX_CTRL;
|
__IO uint8_t Reserved30; // 0x67
|
||||||
__IO uint8_t Reserved29;
|
__IO uint8_t UEP6_TX_LEN; // 0x68
|
||||||
__IO uint8_t UEP7_TX_LEN;
|
__IO uint8_t Reserved31; // 0x69
|
||||||
__IO uint8_t UEP7_TX_CTRL;
|
__IO uint8_t UEP6_TX_CTRL; // 0x6A
|
||||||
__IO uint8_t Reserved30;
|
__IO uint8_t Reserved32; // 0x6B
|
||||||
__IO uint32_t EPX_MODE;
|
__IO uint8_t UEP7_TX_LEN; // 0x6C
|
||||||
|
__IO uint8_t Reserved33; // 0x6D
|
||||||
|
__IO uint8_t UEP7_TX_CTRL; // 0x6E
|
||||||
|
__IO uint8_t Reserved34; // 0x6F
|
||||||
|
__IO uint32_t EPX_MODE; // 0x70
|
||||||
} USBFS_TypeDef;
|
} USBFS_TypeDef;
|
||||||
|
|
||||||
#define UEP_CTRL_LEN(n) (((uint8_t*)&USBFS->UEP0_TX_LEN)[n*4])
|
#define UEP_JMP ((void*)&(USBFS->EP_JMPR) - (void*)&(USBFS->UEP0_DMA))
|
||||||
#define UEP_CTRL_TX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
#define UEP_CTRL_LEN(n) (((volatile uint8_t*)&USBFS->UEP0_TX_LEN)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
#define UEP_CTRL_RX(n) (((uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
#define UEP_DMA(n) (((uint16_t*)&USBFS->UEP0_DMA)[n*2])
|
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
|
#define UEP_DMA(n) (((volatile uint16_t*)&USBFS->UEP0_DMA)[n*2 +((n>4) ? (UEP_JMP /2) : 0)]) // BREAKS FOR EP4!!!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CH32V10x)
|
#if defined(CH32V10x)
|
||||||
#define USBFS_BASE 0x40023400
|
#define USBFS_BASE 0x40023400
|
||||||
#define USB_IRQn USBFS_IRQn
|
#define USB_IRQn USBFS_IRQn
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
__IO uint8_t BASE_CTRL;
|
__IO uint8_t BASE_CTRL;
|
||||||
|
|
@ -109,9 +114,9 @@ typedef struct
|
||||||
__IO uint8_t MIS_ST;
|
__IO uint8_t MIS_ST;
|
||||||
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
__IO uint8_t INT_FG; // "Combined" register in some situations. (ST_FG)
|
||||||
__IO uint8_t INT_ST;
|
__IO uint8_t INT_ST;
|
||||||
__IO uint8_t RX_LEN;
|
__IO uint8_t RX_LEN;
|
||||||
__IO uint8_t Reserved0;
|
__IO uint8_t Reserved0;
|
||||||
__IO uint16_t Reserved1;
|
__IO uint16_t Reserved1;
|
||||||
__IO uint8_t UEP4_1_MOD;
|
__IO uint8_t UEP4_1_MOD;
|
||||||
__IO uint8_t UEP2_3_MOD;
|
__IO uint8_t UEP2_3_MOD;
|
||||||
__IO uint8_t UEP5_6_MOD;
|
__IO uint8_t UEP5_6_MOD;
|
||||||
|
|
@ -133,29 +138,29 @@ typedef struct
|
||||||
__IO uint16_t UEP7_DMA;
|
__IO uint16_t UEP7_DMA;
|
||||||
__IO uint16_t Reserved10;
|
__IO uint16_t Reserved10;
|
||||||
__IO uint16_t UEP0_TX_LEN;
|
__IO uint16_t UEP0_TX_LEN;
|
||||||
__IO uint8_t UEP0_TX_CTRL;
|
__IO uint8_t UEP0_TX_CTRL;
|
||||||
__IO uint8_t Reserved11;
|
__IO uint8_t Reserved11;
|
||||||
__IO uint16_t UEP1_TX_LEN;
|
__IO uint16_t UEP1_TX_LEN;
|
||||||
__IO uint8_t UEP1_TX_CTRL;
|
__IO uint8_t UEP1_TX_CTRL;
|
||||||
__IO uint8_t Reserved12;
|
__IO uint8_t Reserved12;
|
||||||
__IO uint16_t UEP2_TX_LEN;
|
__IO uint16_t UEP2_TX_LEN;
|
||||||
__IO uint8_t UEP2_TX_CTRL;
|
__IO uint8_t UEP2_TX_CTRL;
|
||||||
__IO uint8_t Reserved13;
|
__IO uint8_t Reserved13;
|
||||||
__IO uint16_t UEP3_TX_LEN;
|
__IO uint16_t UEP3_TX_LEN;
|
||||||
__IO uint8_t UEP3_TX_CTRL;
|
__IO uint8_t UEP3_TX_CTRL;
|
||||||
__IO uint8_t Reserved14;
|
__IO uint8_t Reserved14;
|
||||||
__IO uint16_t UEP4_TX_LEN;
|
__IO uint16_t UEP4_TX_LEN;
|
||||||
__IO uint8_t UEP4_TX_CTRL;
|
__IO uint8_t UEP4_TX_CTRL;
|
||||||
__IO uint8_t Reserved15;
|
__IO uint8_t Reserved15;
|
||||||
__IO uint16_t UEP5_TX_LEN;
|
__IO uint16_t UEP5_TX_LEN;
|
||||||
__IO uint8_t UEP5_TX_CTRL;
|
__IO uint8_t UEP5_TX_CTRL;
|
||||||
__IO uint8_t Reserved16;
|
__IO uint8_t Reserved16;
|
||||||
__IO uint16_t UEP6_TX_LEN;
|
__IO uint16_t UEP6_TX_LEN;
|
||||||
__IO uint8_t UEP6_TX_CTRL;
|
__IO uint8_t UEP6_TX_CTRL;
|
||||||
__IO uint8_t Reserved17;
|
__IO uint8_t Reserved17;
|
||||||
__IO uint16_t UEP7_TX_LEN;
|
__IO uint16_t UEP7_TX_LEN;
|
||||||
__IO uint8_t UEP7_TX_CTRL;
|
__IO uint8_t UEP7_TX_CTRL;
|
||||||
__IO uint8_t Reserved18;
|
__IO uint8_t Reserved18;
|
||||||
} USBFS_TypeDef;
|
} USBFS_TypeDef;
|
||||||
|
|
||||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||||
|
|
@ -165,133 +170,155 @@ typedef struct
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined (CH32X03x)
|
#if !defined (CH32X03x)
|
||||||
#define DEBUG_PIN PA8
|
#define DEBUG_PIN PA8
|
||||||
|
|
||||||
#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */
|
#define DEF_USBD_UEP0_SIZE 64 // USB FS device end-point 0 size
|
||||||
#define UEP_SIZE 64
|
#define UEP_SIZE 64
|
||||||
|
|
||||||
#define DEF_UEP_IN 0x80
|
#define DEF_UEP_IN 0x80
|
||||||
#define DEF_UEP_OUT 0x00
|
#define DEF_UEP_OUT 0x00
|
||||||
#define DEF_UEP_BUSY 0x01
|
#define DEF_UEP_BUSY 0x01
|
||||||
#define DEF_UEP_FREE 0x00
|
#define DEF_UEP_FREE 0x00
|
||||||
|
|
||||||
#define DEF_UEP0 0
|
#define DEF_UEP0 0
|
||||||
#define DEF_UEP1 1
|
#define DEF_UEP1 1
|
||||||
#define DEF_UEP2 2
|
#define DEF_UEP2 2
|
||||||
#define DEF_UEP3 3
|
#define DEF_UEP3 3
|
||||||
#define DEF_UEP4 4
|
#define DEF_UEP4 4
|
||||||
#define DEF_UEP5 5
|
#define DEF_UEP5 5
|
||||||
#define DEF_UEP6 6
|
#define DEF_UEP6 6
|
||||||
#define DEF_UEP7 7
|
#define DEF_UEP7 7
|
||||||
#define UNUM_EP 8
|
#define UNUM_EP 8
|
||||||
|
|
||||||
#define USBFS_UEP_T_RES_MASK MASK_UEP_T_RES
|
#define USBFS_UEP_T_RES_MASK MASK_UEP_T_RES
|
||||||
#define USBFS_UEP_T_RES_ACK UEP_T_RES_ACK
|
#define USBFS_UEP_T_RES_ACK UEP_T_RES_ACK
|
||||||
#define USBFS_UEP_T_RES_NAK UEP_T_RES_NAK
|
#define USBFS_UEP_T_RES_NAK UEP_T_RES_NAK
|
||||||
#define USBFS_UEP_T_TOG RB_UEP_T_TOG
|
#define USBFS_UEP_T_TOG RB_UEP_T_TOG
|
||||||
#define USBFS_UEP_T_RES_STALL UEP_T_RES_STALL
|
#define USBFS_UEP_T_RES_STALL UEP_T_RES_STALL
|
||||||
|
|
||||||
#define USBFS_UEP_R_RES_MASK MASK_UEP_R_RES
|
#define USBFS_UEP_R_RES_MASK MASK_UEP_R_RES
|
||||||
#define USBFS_UEP_R_RES_ACK UEP_R_RES_ACK
|
#define USBFS_UEP_R_RES_ACK UEP_R_RES_ACK
|
||||||
#define USBFS_UEP_R_RES_NAK UEP_R_RES_NAK
|
#define USBFS_UEP_R_RES_NAK UEP_R_RES_NAK
|
||||||
#define USBFS_UEP_R_TOG RB_UEP_R_TOG
|
#define USBFS_UEP_R_TOG RB_UEP_R_TOG
|
||||||
#define USBFS_UEP_R_RES_STALL UEP_R_RES_STALL
|
#define USBFS_UEP_R_RES_STALL UEP_R_RES_STALL
|
||||||
|
|
||||||
#define USBFS_UDA_GP_BIT RB_UDA_GP_BIT
|
#define USBFS_UDA_GP_BIT RB_UDA_GP_BIT
|
||||||
#define USBFS_UMS_SUSPEND RB_UMS_SUSPEND
|
#define USBFS_UMS_SUSPEND RB_UMS_SUSPEND
|
||||||
|
|
||||||
#define USBFS_UC_RESET_SIE RB_UC_RESET_SIE
|
#define USBFS_UC_RESET_SIE RB_UC_RESET_SIE
|
||||||
#define USBFS_UC_CLR_ALL RB_UC_CLR_ALL
|
#define USBFS_UC_CLR_ALL RB_UC_CLR_ALL
|
||||||
#define USBFS_UIE_SUSPEND RB_UIE_SUSPEND
|
#define USBFS_UIE_SUSPEND RB_UIE_SUSPEND
|
||||||
#define USBFS_UIE_TRANSFER RB_UIE_TRANSFER
|
#define USBFS_UIE_TRANSFER RB_UIE_TRANSFER
|
||||||
#define USBFS_UIE_BUS_RST RB_UIE_BUS_RST
|
#define USBFS_UIE_BUS_RST RB_UIE_BUS_RST
|
||||||
#define USBFS_UC_INT_BUSY RB_UC_INT_BUSY
|
#define USBFS_UC_INT_BUSY RB_UC_INT_BUSY
|
||||||
#define USBFS_UC_DMA_EN RB_UC_DMA_EN
|
#define USBFS_UC_DMA_EN RB_UC_DMA_EN
|
||||||
#define USBFS_UC_DEV_PU_EN RB_UC_DEV_PU_EN
|
#define USBFS_UC_DEV_PU_EN RB_UC_DEV_PU_EN
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USBFS_UD_PORT_EN RB_UD_PORT_EN
|
#define USBFS_UD_PORT_EN RB_UD_PORT_EN
|
||||||
#define USBFS_UD_PD_DIS RB_UD_PD_DIS
|
#define USBFS_UD_PD_DIS RB_UD_PD_DIS
|
||||||
|
|
||||||
#define USBFS_UEP1_RX_EN RB_UEP1_RX_EN
|
#define USBFS_UEP1_RX_EN RB_UEP1_RX_EN
|
||||||
#define USBFS_UEP2_RX_EN RB_UEP2_RX_EN
|
#define USBFS_UEP2_RX_EN RB_UEP2_RX_EN
|
||||||
#define USBFS_UEP3_RX_EN RB_UEP3_RX_EN
|
#define USBFS_UEP3_RX_EN RB_UEP3_RX_EN
|
||||||
#define USBFS_UEP4_RX_EN RB_UEP4_RX_EN
|
#define USBFS_UEP4_RX_EN RB_UEP4_RX_EN
|
||||||
|
#define USBFS_UEP5_RX_EN RB_UEP5_RX_EN
|
||||||
|
#define USBFS_UEP6_RX_EN RB_UEP6_RX_EN
|
||||||
|
#define USBFS_UEP7_RX_EN RB_UEP7_RX_EN
|
||||||
|
|
||||||
#define USBFS_UEP1_TX_EN RB_UEP1_TX_EN
|
#define USBFS_UEP1_TX_EN RB_UEP1_TX_EN
|
||||||
#define USBFS_UEP2_TX_EN RB_UEP2_TX_EN
|
#define USBFS_UEP2_TX_EN RB_UEP2_TX_EN
|
||||||
#define USBFS_UEP3_TX_EN RB_UEP3_TX_EN
|
#define USBFS_UEP3_TX_EN RB_UEP3_TX_EN
|
||||||
#define USBFS_UEP4_TX_EN RB_UEP4_TX_EN
|
#define USBFS_UEP4_TX_EN RB_UEP4_TX_EN
|
||||||
|
#define USBFS_UEP5_TX_EN RB_UEP5_TX_EN
|
||||||
|
#define USBFS_UEP6_TX_EN RB_UEP6_TX_EN
|
||||||
|
#define USBFS_UEP7_TX_EN RB_UEP7_TX_EN
|
||||||
|
|
||||||
#define CHECK_USBFS_UEP_AUTO_TOG RB_UEP_AUTO_TOG
|
#define CHECK_USBFS_UEP_R_AUTO_TOG RB_UEP_AUTO_TOG
|
||||||
#define CHECK_USBFS_UEP_T_AUTO_TOG RB_UEP_AUTO_TOG
|
#define CHECK_USBFS_UEP_T_AUTO_TOG RB_UEP_AUTO_TOG
|
||||||
// #define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
|
||||||
|
|
||||||
#define USBFS ((USBFS_TypeDef *)USBFS_BASE)
|
#define USBFS ((USBFS_TypeDef *)USBFS_BASE)
|
||||||
|
|
||||||
#ifdef CH32X03x
|
#ifdef CH32X03x
|
||||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
#define EP_JMPR (USBFS_BASE + 64)
|
||||||
#define UEP_CTRL_TX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
#define UEP_JMP ((void*)(EP_JMPR) - (void*)&(USBFS->UEP0_DMA))
|
||||||
#define UEP_CTRL_RX(n) (((volatile uint16_t*)&USBFS->UEP0_CTRL_H)[n*2])
|
#define UEP_CTRL_LEN(n) (((volatile uint8_t*)&USBFS->UEP0_TX_LEN)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_CTRL_H)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
#define DEBUG_PIN PB12
|
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_CTRL_H)[n*4 +((n>4) ? UEP_JMP : 0)])
|
||||||
#define USB_IRQn USBFS_IRQn
|
#define UEP_DMA(n) (((volatile uint16_t*)&USBFS->UEP0_DMA)[n*2 +((n>4) ? (UEP_JMP /2) : 0)]) // DMA for EP4 is tied to EP0 DMA on these chips, so this maceo won't work for it
|
||||||
|
#define DEBUG_PIN PB12
|
||||||
|
#define USB_IRQn USBFS_IRQn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define DEBUG_PIN PB0
|
#define DEBUG_PIN PB0
|
||||||
|
|
||||||
|
#if defined(CH32L103)
|
||||||
|
#define USBFS ((USBFSD_TypeDef *)USBFS_BASE)
|
||||||
|
#define CHECK_USBFS_UEP_R_AUTO_TOG USBFS_UEP_T_AUTO_TOG
|
||||||
|
#define CHECK_USBFS_UEP_T_AUTO_TOG USBFS_UEP_T_AUTO_TOG
|
||||||
|
#else
|
||||||
#define USBFS ((USBOTG_FS_TypeDef *)USBFS_BASE)
|
#define USBFS ((USBOTG_FS_TypeDef *)USBFS_BASE)
|
||||||
|
#define CHECK_USBFS_UEP_T_AUTO_TOG USBOTG_UEP_T_AUTO_TOG
|
||||||
|
#define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
#define UEP_CTRL_LEN(n) (((volatile uint16_t*)&USBFS->UEP0_TX_LEN)[n*2])
|
||||||
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
#define UEP_CTRL_TX(n) (((volatile uint8_t*)&USBFS->UEP0_TX_CTRL)[n*4])
|
||||||
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_RX_CTRL)[n*4])
|
#define UEP_CTRL_RX(n) (((volatile uint8_t*)&USBFS->UEP0_RX_CTRL)[n*4])
|
||||||
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
#define UEP_DMA(n) (((volatile uint32_t*)&USBFS->UEP0_DMA)[n])
|
||||||
|
|
||||||
#define CHECK_USBFS_UEP_T_AUTO_TOG USBOTG_UEP_T_AUTO_TOG
|
#if defined(CH32V20x)
|
||||||
#define CHECK_USBFS_UEP_R_AUTO_TOG USBOTG_UEP_R_AUTO_TOG
|
#define USBFS_UEP_T_RES_MASK USBOTG_UEP_T_RES_MASK
|
||||||
|
#define USBFS_UEP_T_RES_ACK USBOTG_UEP_T_RES_ACK
|
||||||
|
#define USBFS_UEP_T_RES_NAK USBOTG_UEP_T_RES_NAK
|
||||||
|
#define USBFS_UEP_T_TOG USBOTG_UEP_T_TOG
|
||||||
|
#define USBFS_UEP_T_RES_STALL USBOTG_UEP_T_RES_STALL
|
||||||
|
|
||||||
#define USBFS_UEP_T_RES_MASK USBOTG_UEP_T_RES_MASK
|
#define USBFS_UEP_R_RES_MASK USBOTG_UEP_R_RES_MASK
|
||||||
#define USBFS_UEP_T_RES_ACK USBOTG_UEP_T_RES_ACK
|
#define USBFS_UEP_R_RES_ACK USBOTG_UEP_R_RES_ACK
|
||||||
#define USBFS_UEP_T_RES_NAK USBOTG_UEP_T_RES_NAK
|
#define USBFS_UEP_R_RES_NAK USBOTG_UEP_R_RES_NAK
|
||||||
#define USBFS_UEP_T_TOG USBOTG_UEP_T_TOG
|
#define USBFS_UEP_R_TOG USBOTG_UEP_R_TOG
|
||||||
#define USBFS_UEP_T_RES_STALL USBOTG_UEP_T_RES_STALL
|
#define USBFS_UEP_R_RES_STALL USBOTG_UEP_R_RES_STALL
|
||||||
|
|
||||||
#define USBFS_UEP_R_RES_MASK USBOTG_UEP_R_RES_MASK
|
|
||||||
#define USBFS_UEP_R_RES_ACK USBOTG_UEP_R_RES_ACK
|
|
||||||
#define USBFS_UEP_R_RES_NAK USBOTG_UEP_R_RES_NAK
|
|
||||||
#define USBFS_UEP_R_TOG USBOTG_UEP_R_TOG
|
|
||||||
#define USBFS_UEP_R_RES_STALL USBOTG_UEP_R_RES_STALL
|
|
||||||
|
|
||||||
// #define USBFS_UDA_GP_BIT USBOTG_UDA_GP_BIT
|
// #define USBFS_UDA_GP_BIT USBOTG_UDA_GP_BIT
|
||||||
#define USBFS_UMS_SUSPEND USBOTG_UMS_SUSPEND
|
#define USBFS_UMS_SUSPEND USBOTG_UMS_SUSPEND
|
||||||
#define USBFS_UEP1_RX_EN USBOTG_UEP1_RX_EN
|
#define USBFS_UEP1_RX_EN USBOTG_UEP1_RX_EN
|
||||||
#define USBFS_UEP2_RX_EN USBOTG_UEP2_RX_EN
|
#define USBFS_UEP2_RX_EN USBOTG_UEP2_RX_EN
|
||||||
#define USBFS_UEP3_RX_EN USBOTG_UEP3_RX_EN
|
#define USBFS_UEP3_RX_EN USBOTG_UEP3_RX_EN
|
||||||
#define USBFS_UEP4_RX_EN USBOTG_UEP4_RX_EN
|
#define USBFS_UEP4_RX_EN USBOTG_UEP4_RX_EN
|
||||||
|
#define USBFS_UEP5_RX_EN USBOTG_UEP5_RX_EN
|
||||||
|
#define USBFS_UEP6_RX_EN USBOTG_UEP6_RX_EN
|
||||||
|
#define USBFS_UEP7_RX_EN USBOTG_UEP7_RX_EN
|
||||||
|
|
||||||
#define USBFS_UEP1_TX_EN USBOTG_UEP1_TX_EN
|
#define USBFS_UEP1_TX_EN USBOTG_UEP1_TX_EN
|
||||||
#define USBFS_UEP2_TX_EN USBOTG_UEP2_TX_EN
|
#define USBFS_UEP2_TX_EN USBOTG_UEP2_TX_EN
|
||||||
#define USBFS_UEP3_TX_EN USBOTG_UEP3_TX_EN
|
#define USBFS_UEP3_TX_EN USBOTG_UEP3_TX_EN
|
||||||
#define USBFS_UEP4_TX_EN USBOTG_UEP4_TX_EN
|
#define USBFS_UEP4_TX_EN USBOTG_UEP4_TX_EN
|
||||||
|
#define USBFS_UEP5_TX_EN USBOTG_UEP5_TX_EN
|
||||||
|
#define USBFS_UEP6_TX_EN USBOTG_UEP6_TX_EN
|
||||||
|
#define USBFS_UEP7_TX_EN USBOTG_UEP7_TX_EN
|
||||||
|
|
||||||
#define USBFS_UC_RESET_SIE USBOTG_UC_RESET_SIE
|
#define USBFS_UC_RESET_SIE USBOTG_UC_RESET_SIE
|
||||||
#define USBFS_UC_CLR_ALL USBOTG_UC_CLR_ALL
|
#define USBFS_UC_CLR_ALL USBOTG_UC_CLR_ALL
|
||||||
#define USBFS_UIE_SUSPEND USBOTG_UIE_SUSPEND
|
#define USBFS_UIE_SUSPEND USBOTG_UIE_SUSPEND
|
||||||
#define USBFS_UIE_TRANSFER USBOTG_UIE_TRANSFER
|
#define USBFS_UIE_TRANSFER USBOTG_UIE_TRANSFER
|
||||||
#define USBFS_UIE_BUS_RST USBOTG_UIE_BUS_RST
|
#define USBFS_UIE_BUS_RST USBOTG_UIE_BUS_RST
|
||||||
#define USBFS_UC_INT_BUSY USBOTG_UC_INT_BUSY
|
#define USBFS_UC_INT_BUSY USBOTG_UC_INT_BUSY
|
||||||
#define USBFS_UC_DMA_EN USBOTG_UC_DMA_EN
|
#define USBFS_UC_DMA_EN USBOTG_UC_DMA_EN
|
||||||
#define USBFS_UC_DEV_PU_EN USBOTG_UC_DEV_PU_EN
|
#define USBFS_UC_DEV_PU_EN USBOTG_UC_DEV_PU_EN
|
||||||
#define USBFS_UD_PD_DIS USBOTG_UD_PD_DIS
|
#define USBFS_UD_PD_DIS USBOTG_UD_PD_DIS
|
||||||
#define USBFS_UD_PORT_EN USBOTG_UD_PORT_EN
|
#define USBFS_UD_PORT_EN USBOTG_UD_PORT_EN
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CH32V30x_D8C
|
#if defined(CH32L103)
|
||||||
#define USB_IRQn OTG_FS_IRQn
|
#define USB_IRQn USBFS_IRQn
|
||||||
|
#elif defined(CH32V30x_D8C)
|
||||||
|
#define USB_IRQn OTG_FS_IRQn
|
||||||
#else
|
#else
|
||||||
#define USB_IRQn USBHD_IRQn
|
#define USB_IRQn USBHD_IRQn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -313,12 +340,12 @@ typedef struct
|
||||||
#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
|
||||||
#define CUIS_TOKEN_IN 0x2
|
#define CUIS_TOKEN_IN 0x2
|
||||||
#define CUIS_TOKEN_SETUP 0x3
|
#define CUIS_TOKEN_SETUP 0x3
|
||||||
|
|
||||||
#define USBFS_PACKET_SIZE 64
|
#define USBFS_PACKET_SIZE 64
|
||||||
|
|
||||||
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
extern uint32_t USBDEBUG0, USBDEBUG1, USBDEBUG2;
|
||||||
|
|
||||||
|
|
@ -326,11 +353,13 @@ struct _USBState;
|
||||||
|
|
||||||
// Provided functions:
|
// Provided functions:
|
||||||
int USBFSSetup();
|
int USBFSSetup();
|
||||||
|
void USBFSReset();
|
||||||
uint8_t USBFS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
uint8_t USBFS_Endp_DataUp(uint8_t endp, const uint8_t *pbuf, uint16_t len, uint8_t mod);
|
||||||
static inline uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
|
uint8_t * USBFS_GetEPBufferIfAvailable( int endp );
|
||||||
static inline int USBFS_SendEndpoint( int endp, int len );
|
int USBFS_SendEndpoint( int endp, int len );
|
||||||
static inline int USBFS_SendACK( int endp, int tx );
|
int USBFS_SendACK( int endp, int tx );
|
||||||
static inline int USBFS_SendNAK( int endp, int tx );
|
int USBFS_SendNAK( int endp, int tx );
|
||||||
|
int USBFS_SendEndpointNEW( int endp, uint8_t* data, int len, int copy);
|
||||||
|
|
||||||
#if FUSB_USE_DMA7_COPY
|
#if FUSB_USE_DMA7_COPY
|
||||||
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len );
|
static inline void copyBuffer( uint8_t * dest, const uint8_t * src, int len );
|
||||||
|
|
@ -345,18 +374,64 @@ 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 FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
__USBFS_FUN_ATTRIBUTE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
__USBFS_FUN_ATTRIBUTE int HandleInRequest( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||||
__USBFS_FUN_ATTRIBUTE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
__USBFS_FUN_ATTRIBUTE void HandleDataOut( struct _USBState * ctx, int endp, uint8_t * data, int len );
|
||||||
__USBFS_FUN_ATTRIBUTE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
__USBFS_FUN_ATTRIBUTE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum
|
#if FUNCONF_USE_USBPRINTF
|
||||||
|
void HandleUSBInput( int numbytes, uint8_t * data );
|
||||||
|
extern uint8_t usb_inputbuffer[USBFS_PACKET_SIZE];
|
||||||
|
extern int usb_inbuf_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FUSB_MAX_EP_CNT
|
||||||
|
#define FUSB_MAX_EP_CNT 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FUSB_BUFFERS_NUMBER
|
||||||
|
#define FUSB_BUFFERS_NUMBER 1
|
||||||
|
#undef FUSB_EP1_MODE
|
||||||
|
#define FUSB_EP1_MODE 0
|
||||||
|
#undef FUSB_EP2_MODE
|
||||||
|
#define FUSB_EP2_MODE 0
|
||||||
|
#undef FUSB_EP3_MODE
|
||||||
|
#define FUSB_EP3_MODE 0
|
||||||
|
#undef FUSB_EP4_MODE
|
||||||
|
#define FUSB_EP4_MODE 0
|
||||||
|
#undef FUSB_EP5_MODE
|
||||||
|
#define FUSB_EP5_MODE 0
|
||||||
|
#undef FUSB_EP6_MODE
|
||||||
|
#define FUSB_EP6_MODE 0
|
||||||
|
#undef FUSB_EP7_MODE
|
||||||
|
#define FUSB_EP7_MODE 0
|
||||||
|
#warning "You may have forgotten to properly define used EPs in usb_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// high-level-ish abstraction to help dealing with endpoints
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
USBFS_EP_OFF = 0,
|
union {
|
||||||
USBFS_EP_RX = -1,
|
uint8_t * out;
|
||||||
USBFS_EP_TX = 1,
|
uint8_t * rx;
|
||||||
} USBFS_EP_mode;
|
};
|
||||||
|
union {
|
||||||
|
uint8_t * in;
|
||||||
|
uint8_t * tx;
|
||||||
|
};
|
||||||
|
uint8_t mode;
|
||||||
|
volatile uint8_t busy;
|
||||||
|
uint16_t reserved;
|
||||||
|
} USBFS_EP_TypeDef;
|
||||||
|
|
||||||
|
#define USBFS_EP_MODE_TX 4
|
||||||
|
#define USBFS_EP_MODE_TX_DOUBLE 5
|
||||||
|
#define USBFS_EP_MODE_RX 8
|
||||||
|
#define USBFS_EP_MODE_RX_DOUBLE 9
|
||||||
|
#define USBFS_EP_MODE_BDIR 12
|
||||||
|
#define USBFS_EP_MODE_BDIR_DOUBLE 13
|
||||||
|
|
||||||
#ifndef FUSB_EP1_MODE
|
#ifndef FUSB_EP1_MODE
|
||||||
#define FUSB_EP1_MODE 0
|
#define FUSB_EP1_MODE 0
|
||||||
|
|
@ -380,7 +455,6 @@ typedef enum
|
||||||
#define FUSB_EP7_MODE 0
|
#define FUSB_EP7_MODE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
struct _USBState
|
struct _USBState
|
||||||
{
|
{
|
||||||
// Setup Request
|
// Setup Request
|
||||||
|
|
@ -397,23 +471,20 @@ struct _USBState
|
||||||
|
|
||||||
uint8_t* pCtrlPayloadPtr;
|
uint8_t* pCtrlPayloadPtr;
|
||||||
|
|
||||||
uint8_t ENDPOINTS[FUSB_CONFIG_EPS][64];
|
uint8_t ep_buffers[FUSB_BUFFERS_NUMBER][64];
|
||||||
USBFS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
|
||||||
|
|
||||||
#define CTRL0BUFF (USBFSCTX.ENDPOINTS[0])
|
USBFS_EP_TypeDef endpoints[FUSB_MAX_EP_CNT];
|
||||||
|
|
||||||
|
#define CTRL0BUFF (USBFSCTX.ep_buffers[0])
|
||||||
#define pUSBFS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
#define pUSBFS_SetupReqPak ((tusb_control_request_t*)CTRL0BUFF)
|
||||||
|
|
||||||
#if FUSB_HID_INTERFACES > 0
|
#if FUSB_HID_INTERFACES > 0
|
||||||
uint8_t USBFS_HidIdle[FUSB_HID_INTERFACES];
|
uint8_t USBFS_HidIdle[FUSB_HID_INTERFACES];
|
||||||
uint8_t USBFS_HidProtocol[FUSB_HID_INTERFACES];
|
uint8_t USBFS_HidProtocol[FUSB_HID_INTERFACES];
|
||||||
#endif
|
#endif
|
||||||
volatile uint8_t USBFS_Endp_Busy[FUSB_CONFIG_EPS];
|
|
||||||
volatile uint8_t USBFS_errata_dont_send_endpoint_in_window;
|
volatile uint8_t USBFS_errata_dont_send_endpoint_in_window;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct _USBState USBFSCTX;
|
extern struct _USBState USBFSCTX;
|
||||||
|
|
||||||
#include "fsusb.c"
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ struct _USBState USBHSCTX;
|
||||||
volatile uint8_t usb_debug = 0;
|
volatile uint8_t usb_debug = 0;
|
||||||
|
|
||||||
#ifdef CH584_CH585
|
#ifdef CH584_CH585
|
||||||
static inline void mcpy_raw( void *dst, void *start, void *end )
|
static inline void mcpy_raw( void *dst, const void *start, void *end )
|
||||||
{
|
{
|
||||||
__asm__ volatile ( ".insn r 0x0f, 0x7, 0, x0, %3, %0, %1"
|
__asm__ volatile ( ".insn r 0x0f, 0x7, 0, x0, %3, %0, %1"
|
||||||
: "+r"(start), "+r"(dst)
|
: "+r"(start), "+r"(dst)
|
||||||
|
|
@ -15,9 +15,9 @@ static inline void mcpy_raw( void *dst, void *start, void *end )
|
||||||
: "memory" );
|
: "memory" );
|
||||||
}
|
}
|
||||||
|
|
||||||
void * fast_memcpy( void *dst, void *src, uint32_t size )
|
void * fast_memcpy( void *dst, const void *src, uint32_t size )
|
||||||
{
|
{
|
||||||
uint32_t * end = src + size;
|
uint32_t * end = (void *)src + size;
|
||||||
mcpy_raw( dst, src, (void *)end );
|
mcpy_raw( dst, src, (void *)end );
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
|
|
@ -37,6 +37,10 @@ void * fast_memcpy( void *dst, void *src, uint32_t size )
|
||||||
#define USBHS_IRQn USB2_DEVICE_IRQn
|
#define USBHS_IRQn USB2_DEVICE_IRQn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define ANYPRINTF (defined( FUNCONF_USE_DEBUGPRINTF ) && FUNCONF_USE_DEBUGPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_UARTPRINTF ) && FUNCONF_USE_UARTPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF)
|
||||||
|
|
||||||
#if FUSB_USE_HPE // Will it ever work?
|
#if FUSB_USE_HPE // Will it ever work?
|
||||||
// There is an issue with some registers apparently getting lost with HPE, just do it the slow way.
|
// There is an issue with some registers apparently getting lost with HPE, just do it the slow way.
|
||||||
#if defined(CH584_CH585)
|
#if defined(CH584_CH585)
|
||||||
|
|
@ -89,7 +93,9 @@ void USBHS_IRQHandler()
|
||||||
int USBHS_SetupReqLen = USBHSCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength;
|
int USBHS_SetupReqLen = USBHSCTX.USBHS_SetupReqLen = pUSBHS_SetupReqPak->wLength;
|
||||||
int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex;
|
int USBHS_SetupReqIndex = pUSBHS_SetupReqPak->wIndex;
|
||||||
int USBHS_IndexValue = USBHSCTX.USBHS_IndexValue = ( pUSBHS_SetupReqPak->wIndex << 16 ) | pUSBHS_SetupReqPak->wValue;
|
int USBHS_IndexValue = USBHSCTX.USBHS_IndexValue = ( pUSBHS_SetupReqPak->wIndex << 16 ) | pUSBHS_SetupReqPak->wValue;
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf( "[USB] SETUP: %02x %02x %d %04x %08x\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen, USBHS_SetupReqIndex, USBHS_IndexValue );
|
if( usb_debug ) printf( "[USB] SETUP: %02x %02x %d %04x %08x\n", USBHS_SetupReqType, USBHS_SetupReqCode, USBHS_SetupReqLen, USBHS_SetupReqIndex, USBHS_IndexValue );
|
||||||
|
#endif
|
||||||
|
|
||||||
if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
if( ( USBHS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
|
||||||
{
|
{
|
||||||
|
|
@ -256,6 +262,11 @@ void USBHS_IRQHandler()
|
||||||
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;
|
||||||
|
for(int ep = 1; ep < FUSB_MAX_EP_CNT; ep++) {
|
||||||
|
// reset all DATAx
|
||||||
|
UEP_CTRL_RX(ep) &= ~USBHS_UEP_R_TOG_DATA1;
|
||||||
|
UEP_CTRL_TX(ep) &= ~USBHS_UEP_T_TOG_DATA1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Clear or disable one usb feature */
|
/* Clear or disable one usb feature */
|
||||||
|
|
@ -282,11 +293,11 @@ void USBHS_IRQHandler()
|
||||||
{
|
{
|
||||||
/* Clear End-point Feature */
|
/* Clear End-point Feature */
|
||||||
int ep = USBHS_SetupReqIndex & 0xf;
|
int ep = USBHS_SetupReqIndex & 0xf;
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
// UEP_CTRL_TX(ep) = USBHS_UEP_T_RES_STALL;
|
// UEP_CTRL_TX(ep) = USBHS_UEP_T_RES_STALL;
|
||||||
if( USBHS_SetupReqIndex & USBHS_DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) UEP_CTRL_TX(ep) = USBHS_UEP_T_RES_NAK;
|
if( USBHS_SetupReqIndex & USBHS_DEF_UEP_IN && (ctx->endpoints[ep].mode & USBHS_EP_MODE_TX) ) UEP_CTRL_TX(ep) = USBHS_UEP_T_RES_NAK;
|
||||||
else if( USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_RX(ep) = USBHS_UEP_R_RES_ACK;
|
else if( USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBHS_EP_MODE_RX) ) UEP_CTRL_RX(ep) = USBHS_UEP_R_RES_ACK;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
goto sendstall;
|
goto sendstall;
|
||||||
|
|
@ -331,10 +342,10 @@ void USBHS_IRQHandler()
|
||||||
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( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
if( (USBHS_SetupReqIndex & USBHS_DEF_UEP_IN) && ctx->endpoint_mode[ep] == -1 ) UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_STALL;
|
if( (USBHS_SetupReqIndex & USBHS_DEF_UEP_IN) && (ctx->endpoints[ep].mode & USBHS_EP_MODE_TX) ) UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_STALL;
|
||||||
else if( (USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT) && ctx->endpoint_mode[ep] == 1 ) UEP_CTRL_RX(ep) = ( UEP_CTRL_RX(ep) & ~USBHS_UEP_R_RES_MASK ) | USBHS_UEP_R_RES_STALL;
|
else if( (USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT) && (ctx->endpoints[ep].mode & USBHS_EP_MODE_RX) ) UEP_CTRL_RX(ep) = ( UEP_CTRL_RX(ep) & ~USBHS_UEP_R_RES_MASK ) | USBHS_UEP_R_RES_STALL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
goto sendstall;
|
goto sendstall;
|
||||||
|
|
@ -376,10 +387,10 @@ void USBHS_IRQHandler()
|
||||||
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( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
if( USBHS_SetupReqIndex & USBHS_DEF_UEP_IN && ctx->endpoint_mode[ep] == -1 ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBHS_UEP_T_RES_MASK ) == USBHS_UEP_T_RES_STALL;
|
if( USBHS_SetupReqIndex & USBHS_DEF_UEP_IN && (ctx->endpoints[ep].mode & USBHS_EP_MODE_TX) ) ctrl0buff[0] = ( UEP_CTRL_TX(ep) & USBHS_UEP_T_RES_MASK ) == USBHS_UEP_T_RES_STALL;
|
||||||
else if( USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT && ctx->endpoint_mode[ep] == 1 ) ctrl0buff[0] = ( UEP_CTRL_RX(ep) & USBHS_UEP_R_RES_MASK ) == USBHS_UEP_R_RES_STALL;
|
else if( USBHS_SetupReqIndex & USBHS_DEF_UEP_OUT && (ctx->endpoints[ep].mode & USBHS_EP_MODE_RX) ) ctrl0buff[0] = ( UEP_CTRL_RX(ep) & USBHS_UEP_R_RES_MASK ) == USBHS_UEP_R_RES_STALL;
|
||||||
else goto sendstall;
|
else goto sendstall;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -443,16 +454,18 @@ replycomplete:
|
||||||
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;
|
||||||
|
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf( "[USB] TRANSFER, token = %02x, ep = %d, bmRequestType = %02x, bRequest = %02x\n", token, ep, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest );
|
if( usb_debug ) printf( "[USB] TRANSFER, token = %02x, ep = %d, bmRequestType = %02x, bRequest = %02x\n", token, ep, pUSBHS_SetupReqPak->bmRequestType, pUSBHS_SetupReqPak->bRequest );
|
||||||
|
#endif
|
||||||
switch ( token )
|
switch ( token )
|
||||||
{
|
{
|
||||||
case CUIS_TOKEN_IN:
|
case CUIS_TOKEN_IN:
|
||||||
if( ep )
|
if( ep )
|
||||||
{
|
{
|
||||||
if( ep < FUSB_CONFIG_EPS )
|
if( ctx->endpoints[ep].mode )
|
||||||
{
|
{
|
||||||
#if FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
len = HandleInRequest( ctx, ep, ctx->ENDPOINTS[ ep-1 ], 0 );
|
len = HandleInRequest( ctx, ep, ctx->endpoints[ep].in, 0 );
|
||||||
#endif
|
#endif
|
||||||
UEP_CTRL_TX(ep) ^= USBHS_UEP_T_TOG_DATA1;
|
UEP_CTRL_TX(ep) ^= USBHS_UEP_T_TOG_DATA1;
|
||||||
if( len )
|
if( len )
|
||||||
|
|
@ -465,7 +478,7 @@ replycomplete:
|
||||||
{
|
{
|
||||||
UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_NAK;
|
UEP_CTRL_TX(ep) = ( UEP_CTRL_TX(ep) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_NAK;
|
||||||
}
|
}
|
||||||
ctx->USBHS_Endp_Busy[ep] = 0;
|
ctx->endpoints[ep].busy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // EP0
|
else // EP0
|
||||||
|
|
@ -629,7 +642,7 @@ replycomplete:
|
||||||
#endif
|
#endif
|
||||||
UEP_CTRL_RX(ep) = rx_ctrl;
|
UEP_CTRL_RX(ep) = rx_ctrl;
|
||||||
#if FUSB_USER_HANDLERS
|
#if FUSB_USER_HANDLERS
|
||||||
HandleDataOut( ctx, ep, ctx->ENDPOINTS[ep-1], len );
|
HandleDataOut( ctx, ep, ctx->endpoints[ep].out, len );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
USBHS_DONE_RX(ep);
|
USBHS_DONE_RX(ep);
|
||||||
|
|
@ -668,7 +681,9 @@ replycomplete:
|
||||||
}
|
}
|
||||||
else if( intfgst & CRB_UIF_BUS_RST )
|
else if( intfgst & CRB_UIF_BUS_RST )
|
||||||
{
|
{
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf( "[USB] RESET\n" );
|
if( usb_debug ) printf( "[USB] RESET\n" );
|
||||||
|
#endif
|
||||||
/* usb reset interrupt processing */
|
/* usb reset interrupt processing */
|
||||||
ctx->USBHS_DevConfig = 0;
|
ctx->USBHS_DevConfig = 0;
|
||||||
ctx->USBHS_DevAddr = 0;
|
ctx->USBHS_DevAddr = 0;
|
||||||
|
|
@ -681,7 +696,9 @@ replycomplete:
|
||||||
}
|
}
|
||||||
else if( intfgst & CRB_UIF_SUSPEND )
|
else if( intfgst & CRB_UIF_SUSPEND )
|
||||||
{
|
{
|
||||||
|
#if ANYPRINTF
|
||||||
if( usb_debug ) printf( "[USB] SUSPEND\n" );
|
if( usb_debug ) printf( "[USB] SUSPEND\n" );
|
||||||
|
#endif
|
||||||
USBHS->INT_FG = CRB_UIF_SUSPEND;
|
USBHS->INT_FG = CRB_UIF_SUSPEND;
|
||||||
Delay_Us(10);
|
Delay_Us(10);
|
||||||
/* usb suspend interrupt processing */
|
/* usb suspend interrupt processing */
|
||||||
|
|
@ -717,142 +734,168 @@ replycomplete:
|
||||||
|
|
||||||
void USBHS_InternalFinishSetup()
|
void USBHS_InternalFinishSetup()
|
||||||
{
|
{
|
||||||
|
#if USBHS_IMPL == 1
|
||||||
|
USBHS->UEP_CONFIG = 0;
|
||||||
|
#else
|
||||||
|
USBHS->UEP_TX_EN = 0;
|
||||||
|
USBHS->UEP_RX_EN = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP1_MODE
|
#if FUSB_EP1_MODE
|
||||||
USBHSCTX.endpoint_mode[1] = FUSB_EP1_MODE;
|
#if !(defined FUSB_EP1_SIZE && !FUSB_EP1_SIZE)
|
||||||
|
USBHSCTX.endpoints[1].buffer = USBHSCTX.ep1_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[1].mode = FUSB_EP1_MODE;
|
||||||
#ifndef FUSB_EP1_SIZE
|
#ifndef FUSB_EP1_SIZE
|
||||||
USBHS->UEP1_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP1_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[1].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP1_MAX_LEN = FUSB_EP1_SIZE;
|
USBHS->UEP1_MAX_LEN = FUSB_EP1_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[1].size = FUSB_EP1_SIZE;
|
||||||
#if FUSB_EP1_MODE > 0
|
|
||||||
UEP_TX_EN(1);
|
|
||||||
UEP_DMA_TX(1) = (uintptr_t)USBHSCTX.ENDPOINTS[0];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(1);
|
|
||||||
UEP_DMA_RX(1) = (uintptr_t)USBHSCTX.ENDPOINTS[0];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP2_MODE
|
#if FUSB_EP2_MODE
|
||||||
USBHSCTX.endpoint_mode[2] = FUSB_EP2_MODE;
|
#if !(defined FUSB_EP2_SIZE && !FUSB_EP2_SIZE)
|
||||||
|
USBHSCTX.endpoints[2].buffer = USBHSCTX.ep2_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[2].mode = FUSB_EP2_MODE;
|
||||||
#ifndef FUSB_EP2_SIZE
|
#ifndef FUSB_EP2_SIZE
|
||||||
USBHS->UEP2_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP2_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[2].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP2_MAX_LEN = FUSB_EP2_SIZE;
|
USBHS->UEP2_MAX_LEN = FUSB_EP2_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[2].size = FUSB_EP2_SIZE;
|
||||||
#if FUSB_EP2_MODE > 0
|
|
||||||
UEP_TX_EN(2);
|
|
||||||
UEP_DMA_TX(2) = (uintptr_t)USBHSCTX.ENDPOINTS[1];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(2);
|
|
||||||
UEP_DMA_RX(2) = (uintptr_t)USBHSCTX.ENDPOINTS[1];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP3_MODE
|
#if FUSB_EP3_MODE
|
||||||
USBHSCTX.endpoint_mode[3] = FUSB_EP3_MODE;
|
#if !(defined FUSB_EP3_SIZE && !FUSB_EP3_SIZE)
|
||||||
|
USBHSCTX.endpoints[3].buffer = USBHSCTX.ep3_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[3].mode = FUSB_EP3_MODE;
|
||||||
#ifndef FUSB_EP3_SIZE
|
#ifndef FUSB_EP3_SIZE
|
||||||
USBHS->UEP3_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP3_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[3].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP3_MAX_LEN = FUSB_EP3_SIZE;
|
USBHS->UEP3_MAX_LEN = FUSB_EP3_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[3].size = FUSB_EP3_SIZE;
|
||||||
#if FUSB_EP3_MODE > 0
|
|
||||||
UEP_TX_EN(3);
|
|
||||||
UEP_DMA_TX(3) = (uintptr_t)USBHSCTX.ENDPOINTS[2];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(3);
|
|
||||||
UEP_DMA_RX(3) = (uintptr_t)USBHSCTX.ENDPOINTS[2];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP4_MODE
|
#if FUSB_EP4_MODE
|
||||||
USBHSCTX.endpoint_mode[4] = FUSB_EP4_MODE;
|
#if !(defined FUSB_EP4_SIZE && !FUSB_EP4_SIZE)
|
||||||
|
USBHSCTX.endpoints[4].buffer = USBHSCTX.ep4_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[4].mode = FUSB_EP4_MODE;
|
||||||
#ifndef FUSB_EP4_SIZE
|
#ifndef FUSB_EP4_SIZE
|
||||||
USBHS->UEP4_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP4_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[4].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP4_MAX_LEN = FUSB_EP4_SIZE;
|
USBHS->UEP4_MAX_LEN = FUSB_EP4_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[4].size = FUSB_EP4_SIZE;
|
||||||
#if FUSB_EP4_MODE > 0
|
|
||||||
UEP_TX_EN(4);
|
|
||||||
UEP_DMA_TX(4) = (uintptr_t)USBHSCTX.ENDPOINTS[3];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(4);
|
|
||||||
UEP_DMA_RX(4) = (uintptr_t)USBHSCTX.ENDPOINTS[3];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP5_MODE
|
#if FUSB_EP5_MODE
|
||||||
USBHSCTX.endpoint_mode[5] = FUSB_EP5_MODE;
|
#if !(defined FUSB_EP5_SIZE && !FUSB_EP5_SIZE)
|
||||||
|
USBHSCTX.endpoints[5].buffer = USBHSCTX.ep5_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[5].mode = FUSB_EP5_MODE;
|
||||||
#ifndef FUSB_EP5_SIZE
|
#ifndef FUSB_EP5_SIZE
|
||||||
USBHS->UEP5_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP5_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[5].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP5_MAX_LEN = FUSB_EP5_SIZE;
|
USBHS->UEP5_MAX_LEN = FUSB_EP5_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[5].size = FUSB_EP5_SIZE;
|
||||||
#if FUSB_EP5_MODE > 0
|
|
||||||
UEP_TX_EN(5);
|
|
||||||
UEP_DMA_TX(5) = (uintptr_t)USBHSCTX.ENDPOINTS[4];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(5);
|
|
||||||
UEP_DMA_RX(5) = (uintptr_t)USBHSCTX.ENDPOINTS[4];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP6_MODE
|
#if FUSB_EP6_MODE
|
||||||
USBHSCTX.endpoint_mode[6] = FUSB_EP6_MODE;
|
#if !(defined FUSB_EP6_SIZE && !FUSB_EP6_SIZE)
|
||||||
|
USBHSCTX.endpoints[6].buffer = USBHSCTX.ep6_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[6].mode = FUSB_EP6_MODE;
|
||||||
#ifndef FUSB_EP6_SIZE
|
#ifndef FUSB_EP6_SIZE
|
||||||
USBHS->UEP6_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP6_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[6].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP6_MAX_LEN = FUSB_EP6_SIZE;
|
USBHS->UEP6_MAX_LEN = FUSB_EP6_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[6].size = FUSB_EP6_SIZE;
|
||||||
#if FUSB_EP6_MODE > 0
|
|
||||||
UEP_TX_EN(6);
|
|
||||||
UEP_DMA_TX(6) = (uintptr_t)USBHSCTX.ENDPOINTS[5];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(6);
|
|
||||||
UEP_DMA_RX(6) = (uintptr_t)USBHSCTX.ENDPOINTS[5];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FUSB_EP7_MODE
|
#if FUSB_EP7_MODE
|
||||||
USBHSCTX.endpoint_mode[7] = FUSB_EP7_MODE;
|
#if !(defined FUSB_EP7_SIZE && !FUSB_EP7_SIZE)
|
||||||
|
USBHSCTX.endpoints[7].buffer = USBHSCTX.ep7_buffer;
|
||||||
|
#endif
|
||||||
|
USBHSCTX.endpoints[7].mode = FUSB_EP7_MODE;
|
||||||
#ifndef FUSB_EP7_SIZE
|
#ifndef FUSB_EP7_SIZE
|
||||||
USBHS->UEP7_MAX_LEN = FUSB_EP_SIZE;
|
USBHS->UEP7_MAX_LEN = FUSB_EP_SIZE;
|
||||||
|
USBHSCTX.endpoints[7].size = FUSB_EP_SIZE;
|
||||||
#else
|
#else
|
||||||
USBHS->UEP7_MAX_LEN = FUSB_EP7_SIZE;
|
USBHS->UEP7_MAX_LEN = FUSB_EP7_SIZE;
|
||||||
#endif
|
USBHSCTX.endpoints[7].size = FUSB_EP7_SIZE;
|
||||||
#if FUSB_EP7_MODE > 0
|
|
||||||
UEP_TX_EN(7);
|
|
||||||
UEP_DMA_TX(7) = (uintptr_t)USBHSCTX.ENDPOINTS[6];
|
|
||||||
#else
|
|
||||||
UEP_RX_EN(7);
|
|
||||||
UEP_DMA_RX(7) = (uintptr_t)USBHSCTX.ENDPOINTS[6];
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined (FUSB_CONFIG_EPS) || !FUSB_CONFIG_EPS
|
|
||||||
#error You must have at least EP0!
|
|
||||||
#endif
|
|
||||||
|
|
||||||
USBHS->UEP0_DMA = (uintptr_t)USBHSCTX.CTRL0BUFF;
|
USBHS->UEP0_DMA = (uintptr_t)USBHSCTX.CTRL0BUFF;
|
||||||
USBHS->UEP0_MAX_LEN = USBHS_DEF_UEP0_SIZE;
|
USBHS->UEP0_MAX_LEN = USBHS_DEF_UEP0_SIZE;
|
||||||
USBHS->UEP0_T_LEN = 0;
|
UEP_CTRL_LEN(0) = 0;
|
||||||
UEP_TX_EN(0);
|
UEP_TX_EN(0);
|
||||||
UEP_RX_EN(0);
|
UEP_RX_EN(0);
|
||||||
UEP_CTRL_TX(0) = USBHS_UEP_T_RES_NAK;
|
UEP_CTRL_TX(0) = USBHS_UEP_T_RES_NAK;
|
||||||
UEP_CTRL_RX(0) = USBHS_UEP_R_RES_ACK;
|
UEP_CTRL_RX(0) = USBHS_UEP_R_RES_ACK;
|
||||||
|
USBHSCTX.endpoints[0].buffer = USBHSCTX.CTRL0BUFF;
|
||||||
|
USBHSCTX.endpoints[0].mode = USBHS_EP_MODE_TX | USBHS_EP_MODE_RX;
|
||||||
|
|
||||||
for( int i = 1; i < FUSB_CONFIG_EPS; i++ )
|
for( int i = 1; i < FUSB_MAX_EP_CNT; i++ )
|
||||||
{
|
{
|
||||||
if( USBHSCTX.endpoint_mode[i] > 0 )
|
USBHS_EP_TypeDef * endpoint = &USBHSCTX.endpoints[i];
|
||||||
|
UEP_CTRL_LEN(i) = 0;
|
||||||
|
if( endpoint->mode & USBHS_EP_MODE_TX )
|
||||||
{
|
{
|
||||||
UEP_CTRL_TX(i) = USBHS_UEP_T_RES_NAK;
|
UEP_CTRL_TX(i) = USBHS_UEP_T_RES_NAK;
|
||||||
|
UEP_TX_EN(i);
|
||||||
|
UEP_DMA_TX(i) = (uintptr_t)endpoint->buffer;
|
||||||
}
|
}
|
||||||
else if( USBHSCTX.endpoint_mode[i] < 0 )
|
else if( USBHSCTX.endpoints[i].mode & USBHS_EP_MODE_RX )
|
||||||
{
|
{
|
||||||
UEP_CTRL_RX(i) = USBHS_UEP_R_RES_ACK;
|
UEP_CTRL_RX(i) = USBHS_UEP_R_RES_ACK;
|
||||||
|
UEP_RX_EN(i);
|
||||||
|
UEP_DMA_RX(i) = (uintptr_t)endpoint->buffer;
|
||||||
|
|
||||||
}
|
}
|
||||||
USBHSCTX.USBHS_Endp_Busy[i] = 0;
|
|
||||||
|
#if USBHS_IMPL == 1
|
||||||
|
if( endpoint->mode & USBHS_EP_MODE_DOUBLE )
|
||||||
|
{
|
||||||
|
UEP_MODE_DOUBLE(i);
|
||||||
|
if( endpoint->mode & USBHS_EP_MODE_TX )
|
||||||
|
{
|
||||||
|
UEP_DMA_RX(i) = ((uintptr_t)endpoint->buffer) + endpoint->size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UEP_DMA_TX(i) = ((uintptr_t)endpoint->buffer) + endpoint->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( USBHSCTX.endpoints[i].mode & USBHS_EP_MODE_ISO )
|
||||||
|
{
|
||||||
|
UEP_MODE_ISO(i);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if( USBHSCTX.endpoints[i].mode & USBHS_EP_MODE_TX_BURST )
|
||||||
|
{
|
||||||
|
UEP_MODE_TX_BURST(i);
|
||||||
|
}
|
||||||
|
else if( USBHSCTX.endpoints[i].mode & USBHS_EP_MODE_RX_BURST )
|
||||||
|
{
|
||||||
|
UEP_MODE_RX_BURST(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHSCTX.endpoints[i].busy = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -922,15 +965,30 @@ int USBHSSetup()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USBHSReset()
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ( USBHS_IRQn );
|
||||||
|
#if (USBHS_IMPL == 1) // CH32V30x CH565_CH569
|
||||||
|
USBHS->BASE_CTRL = USBHS_UC_CLR_ALL | USBHS_UC_RESET_SIE;
|
||||||
|
Delay_Us(10);
|
||||||
|
USBHS->BASE_CTRL = 0;
|
||||||
|
USBHS->HOST_CTRL = USBHS_UH_PHY_SUSPENDM;
|
||||||
|
#else // CH584_CH585
|
||||||
|
USBHS->BASE_CTRL = USBHS_UD_RST_LINK | USBHS_UD_PHY_SUSPENDM;
|
||||||
|
Delay_Us(10);
|
||||||
|
USBHS->BASE_CTRL = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
static inline uint8_t * USBHS_GetEPBufferIfAvailable( int endp )
|
||||||
{
|
{
|
||||||
if( USBHSCTX.USBHS_Endp_Busy[endp] ) return 0;
|
if( USBHSCTX.endpoints[endp].busy ) return 0;
|
||||||
return USBHSCTX.ENDPOINTS[endp-1];
|
return USBHSCTX.endpoints[endp].in;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int USBHS_SendEndpoint( int endp, int len )
|
static inline int USBHS_SendEndpoint( int endp, int len )
|
||||||
{
|
{
|
||||||
if( USBHSCTX.USBHS_errata_dont_send_endpoint_in_window || USBHSCTX.USBHS_Endp_Busy[endp] ) return -1;
|
if( USBHSCTX.USBHS_errata_dont_send_endpoint_in_window || USBHSCTX.endpoints[endp].busy ) return -1;
|
||||||
// This prevents sending while ep0 is receiving
|
// This prevents sending while ep0 is receiving
|
||||||
if( USBHSCTX.USBHS_SetupReqLen > 0 ) return -2;
|
if( USBHSCTX.USBHS_SetupReqLen > 0 ) return -2;
|
||||||
// Check if in SETUP request
|
// Check if in SETUP request
|
||||||
|
|
@ -938,14 +996,15 @@ static inline int USBHS_SendEndpoint( int endp, int len )
|
||||||
NVIC_DisableIRQ( USBHS_IRQn );
|
NVIC_DisableIRQ( USBHS_IRQn );
|
||||||
UEP_CTRL_LEN( endp ) = len;
|
UEP_CTRL_LEN( endp ) = len;
|
||||||
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||||
USBHSCTX.USBHS_Endp_Busy[endp] = 1;
|
USBHSCTX.endpoints[endp].busy = 1;
|
||||||
NVIC_EnableIRQ( USBHS_IRQn );
|
NVIC_EnableIRQ( USBHS_IRQn );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len, int copy)
|
// If youre sending without copy, make sure data buffer is 4 bytes aligned
|
||||||
|
static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len, int copy )
|
||||||
{
|
{
|
||||||
if( USBHSCTX.USBHS_errata_dont_send_endpoint_in_window || USBHSCTX.USBHS_Endp_Busy[endp] ) return -1;
|
if( USBHSCTX.USBHS_errata_dont_send_endpoint_in_window || USBHSCTX.endpoints[endp].busy ) return -1;
|
||||||
// This prevents sending while ep0 is receiving
|
// This prevents sending while ep0 is receiving
|
||||||
if( USBHSCTX.USBHS_SetupReqLen > 0 ) return USBHSCTX.USBHS_SetupReqLen;
|
if( USBHSCTX.USBHS_SetupReqLen > 0 ) return USBHSCTX.USBHS_SetupReqLen;
|
||||||
|
|
||||||
|
|
@ -953,7 +1012,10 @@ static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len,
|
||||||
{
|
{
|
||||||
if( copy )
|
if( copy )
|
||||||
{
|
{
|
||||||
uint8_t* dest = (endp?USBHSCTX.ENDPOINTS[endp-1]:USBHSCTX.CTRL0BUFF);
|
if( !endp ) USBHS->UEP0_DMA = (uintptr_t)USBHSCTX.CTRL0BUFF;
|
||||||
|
else UEP_DMA_TX( endp ) = (uintptr_t)USBHSCTX.endpoints[endp].in;
|
||||||
|
|
||||||
|
uint8_t* dest = (endp?USBHSCTX.endpoints[endp].in:USBHSCTX.CTRL0BUFF);
|
||||||
copyBuffer( dest, data, len );
|
copyBuffer( dest, data, len );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -965,7 +1027,7 @@ static inline int USBHS_SendEndpointNEW( int endp, const uint8_t* data, int len,
|
||||||
// NVIC_DisableIRQ( USBHS_IRQn );
|
// NVIC_DisableIRQ( USBHS_IRQn );
|
||||||
UEP_CTRL_LEN( endp ) = len;
|
UEP_CTRL_LEN( endp ) = len;
|
||||||
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
UEP_CTRL_TX( endp ) = ( UEP_CTRL_TX( endp ) & ~USBHS_UEP_T_RES_MASK ) | USBHS_UEP_T_RES_ACK;
|
||||||
USBHSCTX.USBHS_Endp_Busy[endp] = 1;
|
USBHSCTX.endpoints[endp].busy = 1;
|
||||||
// NVIC_EnableIRQ( USBHS_IRQn );
|
// NVIC_EnableIRQ( USBHS_IRQn );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1019,4 +1081,3 @@ WEAK int HandleSetupCustom( struct _USBState *ctx, int setup_code )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif // FUNCONF_USE_USBPRINTF
|
#endif // FUNCONF_USE_USBPRINTF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -187,8 +187,10 @@ typedef struct
|
||||||
#define CUIS_TOKEN_IN 0x2
|
#define CUIS_TOKEN_IN 0x2
|
||||||
#define CUIS_TOKEN_SETUP 0x3
|
#define CUIS_TOKEN_SETUP 0x3
|
||||||
|
|
||||||
#define UEP_TX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<n))
|
#define UEP_TX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<n))
|
||||||
#define UEP_RX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<(n+16)))
|
#define UEP_RX_EN(n) USBHS->UEP_CONFIG |= ((uint32_t)(1<<(n+16)))
|
||||||
|
#define UEP_MODE_DOUBLE(n) USBHS->UEP_BUF_MODE |= ((uint32_t)(1<<(n)))
|
||||||
|
#define UEP_MODE_ISO(n) USBHS->UEP_BUF_MODE |= ((uint32_t)(1<<(n+16)))
|
||||||
|
|
||||||
#define USBHS_DONE_TX(n)
|
#define USBHS_DONE_TX(n)
|
||||||
#define USBHS_DONE_RX(n)
|
#define USBHS_DONE_RX(n)
|
||||||
|
|
@ -286,9 +288,11 @@ typedef struct
|
||||||
|
|
||||||
#define USBHS_CHECK_NAK_RX (USBHS->UEP0_RX_CTRL & (1<<6))
|
#define USBHS_CHECK_NAK_RX (USBHS->UEP0_RX_CTRL & (1<<6))
|
||||||
|
|
||||||
#define UEP_RX_LEN(n) (((volatile uint16_t*)&USBHS->UEP1_RX_LEN)[(n-1)*2])
|
#define UEP_RX_LEN(n) (((volatile uint16_t*)&USBHS->UEP1_RX_LEN)[(n-1)*2])
|
||||||
#define UEP_TX_EN(n) USBHS->UEP_TX_EN |= ((uint16_t)(1<<n))
|
#define UEP_TX_EN(n) USBHS->UEP_TX_EN |= ((uint16_t)(1<<n))
|
||||||
#define UEP_RX_EN(n) USBHS->UEP_RX_EN |= ((uint16_t)(1<<n))
|
#define UEP_RX_EN(n) USBHS->UEP_RX_EN |= ((uint16_t)(1<<n))
|
||||||
|
#define UEP_MODE_TX_BURST(n) USBHS->UEP_T_BURST |= ((uint16_t)(1<<n))
|
||||||
|
#define UEP_MODE_RX_BURST(n) USBHS->UEP_R_BURST |= ((uint16_t)(1<<n))
|
||||||
|
|
||||||
#define DEBUG_PIN PB17
|
#define DEBUG_PIN PB17
|
||||||
|
|
||||||
|
|
@ -399,6 +403,10 @@ __HIGH_CODE int HandleSetupCustom( struct _USBState * ctx, int setup_code);
|
||||||
void USBHS_RxReady(int endp);
|
void USBHS_RxReady(int endp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef FUSB_MAX_EP_CNT
|
||||||
|
#define FUSB_MAX_EP_CNT 8
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
USB_SPEED_FULL = 0,
|
USB_SPEED_FULL = 0,
|
||||||
|
|
@ -413,6 +421,40 @@ typedef enum
|
||||||
USBHS_EP_TX = 1,
|
USBHS_EP_TX = 1,
|
||||||
} USBHS_EP_mode;
|
} USBHS_EP_mode;
|
||||||
|
|
||||||
|
// high-level-ish abstraction to help dealing with endpoints
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint8_t * out;
|
||||||
|
uint8_t * rx;
|
||||||
|
uint8_t * in;
|
||||||
|
uint8_t * tx;
|
||||||
|
uint8_t * buffer;
|
||||||
|
};
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t mode;
|
||||||
|
volatile uint8_t busy;
|
||||||
|
} USBHS_EP_TypeDef;
|
||||||
|
|
||||||
|
#define USBHS_EP_MODE_TX 4
|
||||||
|
#define USBHS_EP_MODE_RX 8
|
||||||
|
|
||||||
|
#if USBHS_IMPL == 1
|
||||||
|
#define USBHS_EP_MODE_TX_DOUBLE 5
|
||||||
|
#define USBHS_EP_MODE_TX_ISO 6
|
||||||
|
#define USBHS_EP_MODE_RX_DOUBLE 9
|
||||||
|
#define USBHS_EP_MODE_RX_ISO 10
|
||||||
|
#define USBHS_EP_MODE_DOUBLE 1
|
||||||
|
#define USBHS_EP_MODE_ISO 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USBHS_IMPL == 2
|
||||||
|
// https://www.wch.cn/bbs/thread-150494-1.html
|
||||||
|
#define USBHS_EP_MODE_BURST 1
|
||||||
|
#define USBHS_EP_MODE_TX_BURST 5
|
||||||
|
#define USBHS_EP_MODE_RX_BURST 9
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FUSB_EP1_MODE
|
#ifndef FUSB_EP1_MODE
|
||||||
#define FUSB_EP1_MODE 0
|
#define FUSB_EP1_MODE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -438,7 +480,120 @@ typedef enum
|
||||||
struct _USBState
|
struct _USBState
|
||||||
{
|
{
|
||||||
__attribute__ ((aligned(4))) uint8_t CTRL0BUFF[64];
|
__attribute__ ((aligned(4))) uint8_t CTRL0BUFF[64];
|
||||||
__attribute__ ((aligned(4))) uint8_t ENDPOINTS[FUSB_CONFIG_EPS-1][FUSB_EP_SIZE];
|
|
||||||
|
#if FUSB_EP1_MODE
|
||||||
|
#if FUSB_EP1_SIZE
|
||||||
|
#if FUSB_EP1_MODE & 1
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep1_buffer[FUSB_EP1_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep1_buffer[FUSB_EP1_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP1_SIZE) && !FUSB_EP1_SIZE)
|
||||||
|
#if (FUSB_EP1_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep1_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep1_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP2_MODE
|
||||||
|
#if FUSB_EP2_SIZE
|
||||||
|
#if (FUSB_EP2_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep2_buffer[FUSB_EP2_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep2_buffer[FUSB_EP2_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP2_SIZE) && !FUSB_EP2_SIZE)
|
||||||
|
#if (FUSB_EP2_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep2_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep2_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP3_MODE
|
||||||
|
#if FUSB_EP3_SIZE
|
||||||
|
#if (FUSB_EP3_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep3_buffer[FUSB_EP3_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep3_buffer[FUSB_EP3_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP3_SIZE) && !FUSB_EP3_SIZE)
|
||||||
|
#if (FUSB_EP3_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep3_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep3_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP4_MODE
|
||||||
|
#if FUSB_EP4_SIZE
|
||||||
|
#if (FUSB_EP4_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep4_buffer[FUSB_EP4_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep4_buffer[FUSB_EP4_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP4_SIZE) && !FUSB_EP4_SIZE)
|
||||||
|
#if (FUSB_EP4_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep4_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep4_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP5_MODE
|
||||||
|
#if FUSB_EP5_SIZE
|
||||||
|
#if (FUSB_EP5_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep5_buffer[FUSB_EP5_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep5_buffer[FUSB_EP5_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP5_SIZE) && !FUSB_EP5_SIZE)
|
||||||
|
#if (FUSB_EP5_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep5_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep5_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP6_MODE
|
||||||
|
#if FUSB_EP6_SIZE
|
||||||
|
#if (FUSB_EP6_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep6_buffer[FUSB_EP6_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep6_buffer[FUSB_EP6_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP6_SIZE) && !FUSB_EP6_SIZE)
|
||||||
|
#if (FUSB_EP6_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep6_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep6_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP7_MODE
|
||||||
|
#if FUSB_EP7_SIZE
|
||||||
|
#if (FUSB_EP7_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep7_buffer[FUSB_EP7_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep7_buffer[FUSB_EP7_SIZE];
|
||||||
|
#endif
|
||||||
|
#elif !(defined(FUSB_EP7_SIZE) && !FUSB_EP7_SIZE)
|
||||||
|
#if (FUSB_EP7_MODE & 1)
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep7_buffer[FUSB_EP_SIZE*2];
|
||||||
|
#else
|
||||||
|
__attribute__ ((aligned(4))) uint8_t ep7_buffer[FUSB_EP_SIZE];
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
USBHS_EP_TypeDef endpoints[FUSB_MAX_EP_CNT];
|
||||||
// Setup Request
|
// Setup Request
|
||||||
uint8_t USBHS_SetupReqCode;
|
uint8_t USBHS_SetupReqCode;
|
||||||
uint8_t USBHS_SetupReqType;
|
uint8_t USBHS_SetupReqType;
|
||||||
|
|
@ -452,17 +607,13 @@ struct _USBState
|
||||||
uint8_t USBHS_DevEnumStatus;
|
uint8_t USBHS_DevEnumStatus;
|
||||||
|
|
||||||
uint8_t* pCtrlPayloadPtr;
|
uint8_t* pCtrlPayloadPtr;
|
||||||
|
|
||||||
|
|
||||||
USBHS_EP_mode endpoint_mode[FUSB_CONFIG_EPS+1]; // IN -1, OUT 1, OFF 0
|
|
||||||
|
|
||||||
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)USBHSCTX.CTRL0BUFF)
|
#define pUSBHS_SetupReqPak ((tusb_control_request_t*)USBHSCTX.CTRL0BUFF)
|
||||||
|
|
||||||
#if FUSB_HID_INTERFACES > 0
|
#if FUSB_HID_INTERFACES > 0
|
||||||
uint8_t USBHS_HidIdle[FUSB_HID_INTERFACES];
|
uint8_t USBHS_HidIdle[FUSB_HID_INTERFACES];
|
||||||
uint8_t USBHS_HidProtocol[FUSB_HID_INTERFACES];
|
uint8_t USBHS_HidProtocol[FUSB_HID_INTERFACES];
|
||||||
#endif
|
#endif
|
||||||
volatile uint8_t USBHS_Endp_Busy[FUSB_CONFIG_EPS];
|
|
||||||
volatile uint8_t USBHS_errata_dont_send_endpoint_in_window;
|
volatile uint8_t USBHS_errata_dont_send_endpoint_in_window;
|
||||||
volatile uint64_t USBHS_sof_timestamp;
|
volatile uint64_t USBHS_sof_timestamp;
|
||||||
};
|
};
|
||||||
|
|
@ -472,4 +623,3 @@ extern struct _USBState USBHSCTX;
|
||||||
#include "hsusb.c"
|
#include "hsusb.c"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
415
inc/extralibs/rtc.h
Normal file
415
inc/extralibs/rtc.h
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
// MIT License
|
||||||
|
// Copyright (c) 2025 UniTheCat
|
||||||
|
// This library supports two WCH hardware implementations for an RTC
|
||||||
|
// and distinguishes between them using compile-time flags.
|
||||||
|
#include <stdio.h>
|
||||||
|
#if defined(CH32V10x)
|
||||||
|
#include "ch32v103hw.h"
|
||||||
|
#elif defined (CH32L103)
|
||||||
|
#include "ch32l103hw.h"
|
||||||
|
#elif defined (CH32V20x)
|
||||||
|
#include "ch32v20xhw.h"
|
||||||
|
#elif defined (CH32V30x)
|
||||||
|
#include "ch32v30xhw.h"
|
||||||
|
#elif defined (CH5xx)
|
||||||
|
#include "ch5xxhw.h"
|
||||||
|
#else
|
||||||
|
#error "Currently unsupported RTC"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(RTC_CLOCK_SOURCE_LSI) && !defined(RTC_CLOCK_SOURCE_LSE)
|
||||||
|
#define RTC_CLOCK_SOURCE_LSI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RTC_CLOCK_TICKS_PER_SECOND 32768
|
||||||
|
|
||||||
|
#ifndef CH5xx // No custom RTC divider support on CH5xx
|
||||||
|
#ifndef RTC_CLOCK_TICKS_PER_INCREMENT
|
||||||
|
#define RTC_CLOCK_TICKS_PER_INCREMENT RTC_CLOCK_TICKS_PER_SECOND
|
||||||
|
#endif
|
||||||
|
#define RTC_INCREMENTS_PER_SECOND (RTC_CLOCK_TICKS_PER_SECOND / RTC_CLOCK_TICKS_PER_INCREMENT)
|
||||||
|
#endif // !CH5xx
|
||||||
|
|
||||||
|
#define SECONDS_PER_MINUTE 60
|
||||||
|
#define SECONDS_PER_HOUR 3600
|
||||||
|
#define SECONDS_PER_DAY 86400
|
||||||
|
|
||||||
|
#define IS_LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || ((year) % 400 == 0))
|
||||||
|
|
||||||
|
// Array of days in each month (non-leap year)
|
||||||
|
const u8 DAYS_IN_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u16 year;
|
||||||
|
u8 month;
|
||||||
|
u8 day;
|
||||||
|
} rtc_date_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 hr;
|
||||||
|
u8 min;
|
||||||
|
u8 sec;
|
||||||
|
u16 ms;
|
||||||
|
} rtc_time_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
rtc_date_t date;
|
||||||
|
rtc_time_t time;
|
||||||
|
} rtc_datetime_t;
|
||||||
|
|
||||||
|
const rtc_date_t date_reference = {2020, 1, 1};
|
||||||
|
|
||||||
|
// calculate days of the current year. eg. 2020-02-05 is 36 day
|
||||||
|
u32 RTC_days_of_year(u16 year, u8 month, u8 day) {
|
||||||
|
u32 day_of_year = 0;
|
||||||
|
|
||||||
|
// Add days from January to month-1
|
||||||
|
for (u8 m = 0; m < month - 1; m++) {
|
||||||
|
day_of_year += DAYS_IN_MONTH[m];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add extra day for February (full month) if it's a leap year
|
||||||
|
if (month > 2 && IS_LEAP_YEAR(year)) {
|
||||||
|
day_of_year += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add days in the current month
|
||||||
|
day_of_year += day;
|
||||||
|
|
||||||
|
return day_of_year;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 RTC_get_seconds(u16 year, u8 month, u8 day, u8 hr, u8 min, u8 sec) {
|
||||||
|
//# Validate input
|
||||||
|
if (month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||||
|
hr > 23 || min > 59 || sec > 59 || year < 1970) { return 0; }
|
||||||
|
|
||||||
|
// calculate days of the current year, -1 for 0-based days
|
||||||
|
u32 days = RTC_days_of_year(year, month, day) - 1;
|
||||||
|
|
||||||
|
// add the days count excluding the current year
|
||||||
|
// (start from epoch time 1970-01-01 00:00:00)
|
||||||
|
for (int y=1970; y < year; y++) {
|
||||||
|
days += IS_LEAP_YEAR(y) ? 366 : 365;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate total seconds
|
||||||
|
return days * SECONDS_PER_DAY +
|
||||||
|
hr * SECONDS_PER_HOUR +
|
||||||
|
min * SECONDS_PER_MINUTE + sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_time_t RTC_get_time(u32 total_seconds, u16 ms) {
|
||||||
|
u32 minutes = total_seconds / 60;
|
||||||
|
|
||||||
|
return (rtc_time_t) {
|
||||||
|
.sec = total_seconds % 60,
|
||||||
|
.min = minutes % 60,
|
||||||
|
.hr = (minutes / 60) % 24,
|
||||||
|
.ms = ms
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc_date_t RTC_get_date(u32 total_seconds) {
|
||||||
|
rtc_date_t output = {
|
||||||
|
.year = date_reference.year,
|
||||||
|
.month = date_reference.month,
|
||||||
|
.day = date_reference.day
|
||||||
|
};
|
||||||
|
|
||||||
|
// Days since epoch
|
||||||
|
u32 days_remaining = total_seconds / SECONDS_PER_DAY;
|
||||||
|
|
||||||
|
// Find the year
|
||||||
|
while(1) {
|
||||||
|
u16 days_in_year = IS_LEAP_YEAR(output.year) ? 366 : 365;
|
||||||
|
if (days_remaining < days_in_year) break;
|
||||||
|
days_remaining -= days_in_year;
|
||||||
|
output.year++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the month
|
||||||
|
for (u8 m = 0; m < 12; m++) {
|
||||||
|
u8 days_in_month = DAYS_IN_MONTH[m];
|
||||||
|
if (m == 1 && IS_LEAP_YEAR(output.year)) days_in_month = 29;
|
||||||
|
if (days_remaining < days_in_month) break;
|
||||||
|
|
||||||
|
days_remaining -= days_in_month;
|
||||||
|
output.month++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add 1 because days_remaining is 0-based
|
||||||
|
output.day = days_remaining + 1;
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_print_date(rtc_date_t date, char *delimiter) {
|
||||||
|
printf("%04d", date.year);
|
||||||
|
printf("%s%02d", delimiter, date.month);
|
||||||
|
printf("%s%02d", delimiter, date.day);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_print_time(rtc_time_t time) {
|
||||||
|
printf("%02d:%02d:%02d.%03d",
|
||||||
|
time.hr, time.min, time.sec, time.ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! ####################################
|
||||||
|
//! CORE FUNCTION
|
||||||
|
//! ####################################
|
||||||
|
|
||||||
|
// There are potential speed improvements to this function, such as not resetting the
|
||||||
|
// backup domain or the LSI/LSE clock if they are already enabled. However, after
|
||||||
|
// testing with standby resets, it either didn't work at all or stopped working
|
||||||
|
// after a few minutes. Tread carefully!
|
||||||
|
void RTC_init() {
|
||||||
|
#ifdef CH5xx
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R32_RTC_TRIG = 0;
|
||||||
|
R32_RTC_CTRL |= RB_RTC_LOAD_HI;
|
||||||
|
R32_RTC_CTRL |= RB_RTC_LOAD_LO;
|
||||||
|
R8_RTC_MODE_CTRL |= RB_RTC_TRIG_EN; //enable RTC trigger
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
RCC->APB1PCENR |= RCC_APB1Periph_PWR | RCC_APB1Periph_BKP;
|
||||||
|
|
||||||
|
// backup domain enable
|
||||||
|
PWR->CTLR |= PWR_CTLR_DBP;
|
||||||
|
|
||||||
|
// prepare to configure clock source
|
||||||
|
RCC->BDCTLR |= RCC_BDRST;
|
||||||
|
RCC->BDCTLR &=~ RCC_BDRST;
|
||||||
|
|
||||||
|
#ifdef RTC_CLOCK_SOURCE_LSI
|
||||||
|
// Takes 300us, even if already enabled
|
||||||
|
RCC->RSTSCKR |= RCC_LSION;
|
||||||
|
while ( !(RCC->RSTSCKR & RCC_LSIRDY) );
|
||||||
|
|
||||||
|
// Set clock source for RTC
|
||||||
|
RCC->BDCTLR &=~ RCC_RTCSEL;
|
||||||
|
RCC->BDCTLR |= RCC_RTCSEL_LSI;
|
||||||
|
#elif defined(RTC_CLOCK_SOURCE_LSE)
|
||||||
|
// Enable LSE
|
||||||
|
RCC->BDCTLR |= RCC_LSEON;
|
||||||
|
uint16_t timeout = 0;
|
||||||
|
while ( !(RCC->BDCTLR & RCC_LSERDY) ) {
|
||||||
|
Delay_Ms(1);
|
||||||
|
timeout++;
|
||||||
|
if (timeout > 1000) {
|
||||||
|
printf("Could not start LSE.\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set clock source for RTC
|
||||||
|
RCC->BDCTLR &=~ RCC_RTCSEL;
|
||||||
|
RCC->BDCTLR |= RCC_RTCSEL_LSE;
|
||||||
|
#else
|
||||||
|
#error "No RTC clock source defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RCC->BDCTLR |= RCC_RTCEN;
|
||||||
|
|
||||||
|
// Wait until we can safely communicate with RTC registers
|
||||||
|
RTC->CTLRL &= ~RTC_FLAG_RSF;
|
||||||
|
while (!(RTC->CTLRL & RTC_FLAG_RSF));
|
||||||
|
|
||||||
|
// Reset alarm, second, and overflow flags
|
||||||
|
RTC->CTLRL &= ~(RTC_CTLRL_ALRF | RTC_CTLRL_SECF | RTC_CTLRL_OWF);
|
||||||
|
|
||||||
|
RTC_CONFIG_CHANGE(
|
||||||
|
// Set prescaler value
|
||||||
|
RTC->PSCRH = ((RTC_CLOCK_TICKS_PER_INCREMENT-1) & PRLH_MSB_MASK) >> 16;
|
||||||
|
RTC->PSCRL = (RTC_CLOCK_TICKS_PER_INCREMENT-1) & RTC_LSB_MASK;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CH5xx
|
||||||
|
void RTC_getCounter(u16 *days, u16 *seconds_2s, u16 *ticks_32k) {
|
||||||
|
u16 days_1, days_2, seconds_2s_1, seconds_2s_2, ticks;
|
||||||
|
|
||||||
|
// properly deal with asynchronous read of multiple registers in
|
||||||
|
// rollover case
|
||||||
|
days_1 = R32_RTC_CNT_DAY;
|
||||||
|
seconds_2s_1 = R16_RTC_CNT_2S;
|
||||||
|
ticks = R16_RTC_CNT_32K;
|
||||||
|
days_2 = R32_RTC_CNT_DAY;
|
||||||
|
seconds_2s_2 = R16_RTC_CNT_2S;
|
||||||
|
|
||||||
|
if (days_1 != days_2 || seconds_2s_1 != seconds_2s_2) {
|
||||||
|
// Rollover occurred, re-read all values
|
||||||
|
*days = R32_RTC_CNT_DAY;
|
||||||
|
*seconds_2s = R16_RTC_CNT_2S;
|
||||||
|
*ticks_32k = R16_RTC_CNT_32K;
|
||||||
|
} else {
|
||||||
|
// No rollover, use the captured values
|
||||||
|
*days = days_1;
|
||||||
|
*seconds_2s = seconds_2s_1;
|
||||||
|
*ticks_32k = ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
uint32_t RTC_getCounter(void) {
|
||||||
|
uint16_t high1, high2, low;
|
||||||
|
uint32_t s;
|
||||||
|
|
||||||
|
// Wait for registers to be synchronized
|
||||||
|
RTC->CTLRL &= ~RTC_FLAG_RSF;
|
||||||
|
while (!(RTC->CTLRL & RTC_FLAG_RSF));
|
||||||
|
|
||||||
|
high1 = RTC->CNTH;
|
||||||
|
low = RTC->CNTL;
|
||||||
|
high2 = RTC->CNTH;
|
||||||
|
|
||||||
|
// properly deal with asynchronous read of multiple registers in
|
||||||
|
// rollover case
|
||||||
|
if (high1 != high2) {
|
||||||
|
s = (high2 << 16) | RTC->CNTL;
|
||||||
|
} else {
|
||||||
|
s = (high1 << 16) | low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rtc_datetime_t RTC_getDateTime() {
|
||||||
|
#ifdef CH5xx
|
||||||
|
u16 days, seconds_2s, ticks_32k;
|
||||||
|
RTC_getCounter(&days, &seconds_2s, &ticks_32k);
|
||||||
|
u32 total_seconds = (days * SECONDS_PER_DAY) + (seconds_2s * 2) + (ticks_32k / RTC_CLOCK_TICKS_PER_SECOND);
|
||||||
|
u16 ms = ((ticks_32k % RTC_CLOCK_TICKS_PER_SECOND) * 1000UL) / RTC_CLOCK_TICKS_PER_SECOND;
|
||||||
|
#else
|
||||||
|
u32 count = RTC_getCounter();
|
||||||
|
u32 total_seconds = count / RTC_INCREMENTS_PER_SECOND;
|
||||||
|
u16 ms = ((count % RTC_INCREMENTS_PER_SECOND) * 1000UL) / RTC_INCREMENTS_PER_SECOND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rtc_date_t date = RTC_get_date(total_seconds);
|
||||||
|
rtc_time_t time = RTC_get_time(total_seconds, ms);
|
||||||
|
return (rtc_datetime_t) {date, time};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CH5xx
|
||||||
|
void RTC_setDayCounter(u32 day_counter) {
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R32_RTC_TRIG = day_counter - 1;
|
||||||
|
R8_RTC_MODE_CTRL |= RB_RTC_LOAD_HI;
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_setTimeCounter(u32 time_counter) {
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R32_RTC_TRIG = time_counter;
|
||||||
|
R8_RTC_MODE_CTRL |= RB_RTC_LOAD_LO;
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif // CH5xx
|
||||||
|
|
||||||
|
void RTC_setDateTime(rtc_datetime_t *datetime) {
|
||||||
|
// Clip year
|
||||||
|
u16 year_min = date_reference.year;
|
||||||
|
#ifdef CH5xx
|
||||||
|
u16 year_max = date_reference.year + 0x3FFF / 365; // 14 bits = ~44 years
|
||||||
|
#else
|
||||||
|
u16 year_max = date_reference.year + 0xFFFFFFFF / 60 / 60 / 24 / 365 / RTC_INCREMENTS_PER_SECOND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (datetime->date.year < year_min) datetime->date.year = year_min;
|
||||||
|
if (datetime->date.year > year_max) datetime->date.year = year_max;
|
||||||
|
|
||||||
|
#ifdef CH5xx
|
||||||
|
u32 days_counter = 0;
|
||||||
|
// Add days for complete years from year_min to year-1
|
||||||
|
for (u16 y = year_min; y < datetime->date.year; y++) {
|
||||||
|
days_counter += IS_LEAP_YEAR(y) ? 366 : 365;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add days in the current year
|
||||||
|
days_counter += RTC_days_of_year(datetime->date.year, datetime->date.month, datetime->date.day);
|
||||||
|
RTC_setDayCounter(days_counter);
|
||||||
|
|
||||||
|
u16 seconds = datetime->time.hr * 3600 + datetime->time.min * 60 + datetime->time.sec;
|
||||||
|
u16 time_2s = seconds / 2;
|
||||||
|
u32 time_32k = (seconds % 2) * RTC_CLOCK_TICKS_PER_SECOND + datetime->time.ms * RTC_CLOCK_TICKS_PER_SECOND / 1000;
|
||||||
|
u32 time_counter = (time_2s << 16) | (time_32k & 0xFFFF);
|
||||||
|
RTC_setTimeCounter(time_counter);
|
||||||
|
|
||||||
|
#else
|
||||||
|
u32 total_seconds = RTC_get_seconds(datetime->date.year, datetime->date.month, datetime->date.day,
|
||||||
|
datetime->time.hr, datetime->time.min, datetime->time.sec);
|
||||||
|
u32 increments = total_seconds * RTC_INCREMENTS_PER_SECOND +
|
||||||
|
(datetime->time.ms * RTC_INCREMENTS_PER_SECOND) / 1000;
|
||||||
|
RTC_CONFIG_CHANGE(
|
||||||
|
RTC->CNTH = increments >> 16;
|
||||||
|
RTC->CNTL = increments & RTC_LSB_MASK;
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CH5xx
|
||||||
|
// Set RTC to generate an interrupt after cyc ticks.
|
||||||
|
// Keep RTCTrigger function name for legacy reasons
|
||||||
|
void RTCTrigger(uint32_t cyc)
|
||||||
|
{
|
||||||
|
//get the rtc current time
|
||||||
|
uint32_t alarm = (uint32_t) R16_RTC_CNT_LSI | ( (uint32_t) R16_RTC_CNT_DIV1 << 16 );
|
||||||
|
alarm += cyc;
|
||||||
|
|
||||||
|
if( alarm > RTC_MAX_COUNT ) {
|
||||||
|
alarm -= RTC_MAX_COUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_SAFE_ACCESS(
|
||||||
|
R32_RTC_TRIG = alarm;
|
||||||
|
);
|
||||||
|
}
|
||||||
|
void RTC_setAlarm(u32 increments) { RTCTrigger(increments); }
|
||||||
|
#else
|
||||||
|
void RTC_setAlarm(u32 increments) {
|
||||||
|
// Make sure AFIO power is on for EXTI interrupts
|
||||||
|
RCC->APB2PCENR |= RCC_AFIOEN;
|
||||||
|
|
||||||
|
// Clear any pending alarm interrupt before reconfiguring
|
||||||
|
NVIC_ClearPendingIRQ(RTCAlarm_IRQn);
|
||||||
|
EXTI->INTFR = EXTI_Line17;
|
||||||
|
RTC->CTLRL &= ~RTC_CTLRL_ALRF;
|
||||||
|
|
||||||
|
RTC_CONFIG_CHANGE(
|
||||||
|
RTC->ALRMH = increments >> 16;
|
||||||
|
RTC->ALRML = increments & RTC_LSB_MASK;
|
||||||
|
);
|
||||||
|
|
||||||
|
// A few RTC ticks are necessary before enabling EXTI, as they are on two
|
||||||
|
// different clock domains and <my current working theory> EXTI fires prematurely
|
||||||
|
// on stale alarm register values?
|
||||||
|
// What is weird is that waiting for the register synchronization flag (RSF) to be
|
||||||
|
// set is not sufficient and doesn't appear to make any difference for the timing!
|
||||||
|
Delay_Us(100);
|
||||||
|
|
||||||
|
EXTI->INTENR |= EXTI_Line17;
|
||||||
|
EXTI->RTENR |= EXTI_Line17; // RTC alarm is rising-edge
|
||||||
|
NVIC_EnableIRQ(RTCAlarm_IRQn);
|
||||||
|
RTC->CTLRH |= RTC_CTLRH_ALRIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_setAlarmAbsolute(rtc_datetime_t *datetime) {
|
||||||
|
u32 total_seconds = RTC_get_seconds(datetime->date.year, datetime->date.month, datetime->date.day,
|
||||||
|
datetime->time.hr, datetime->time.min, datetime->time.sec);
|
||||||
|
u32 increments = total_seconds * RTC_INCREMENTS_PER_SECOND +
|
||||||
|
(datetime->time.ms * RTC_INCREMENTS_PER_SECOND) / 1000;
|
||||||
|
RTC_setAlarm(increments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTC_setAlarmRelative(u16 seconds_from_now, u16 milliseconds_from_now) {
|
||||||
|
u32 current = RTC_getCounter();
|
||||||
|
u32 alarm_value = current + (seconds_from_now * RTC_INCREMENTS_PER_SECOND) +
|
||||||
|
(milliseconds_from_now * RTC_INCREMENTS_PER_SECOND) / 1000;
|
||||||
|
RTC_setAlarm(alarm_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !CH5xx
|
||||||
|
|
@ -11,13 +11,17 @@
|
||||||
#include "font_8x8.h"
|
#include "font_8x8.h"
|
||||||
|
|
||||||
// comfortable packet size for this OLED
|
// comfortable packet size for this OLED
|
||||||
|
#if SSD1306_3WIRE_SPI && !SSD1306_SOFT_SPI
|
||||||
|
#define SSD1306_PSZ 8
|
||||||
|
#else
|
||||||
#define SSD1306_PSZ 32
|
#define SSD1306_PSZ 32
|
||||||
|
#endif
|
||||||
|
|
||||||
#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_72X40) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1107_128x128) && !(defined(SSD1306_W) && defined(SSD1306_H) && defined(SSD1306_OFFSET) )
|
#if !defined (SSD1306_64X32) && !defined (SSD1306_72X40) && !defined (SSD1306_128X32) && !defined (SSD1306_128X64) && !defined (SH1106_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
|
||||||
|
|
||||||
|
|
@ -48,6 +52,15 @@
|
||||||
#define SSD1306_OFFSET 0
|
#define SSD1306_OFFSET 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SH1106_128x64
|
||||||
|
#define SH1107
|
||||||
|
#define SSD1306_FULLUSE
|
||||||
|
#define SSD1306_W 128
|
||||||
|
#define SSD1306_H 64
|
||||||
|
#define SSD1306_FULLUSE
|
||||||
|
#define SSD1306_OFFSET 2
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SH1107_128x128
|
#ifdef SH1107_128x128
|
||||||
#define SH1107
|
#define SH1107
|
||||||
#define SSD1306_FULLUSE
|
#define SSD1306_FULLUSE
|
||||||
|
|
@ -112,6 +125,7 @@ uint8_t ssd1306_data(uint8_t *data, int sz)
|
||||||
// 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
|
||||||
|
|
@ -206,8 +220,8 @@ void ssd1306_refresh(void)
|
||||||
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 | (SSD1306_OFFSET&0xf) );
|
||||||
ssd1306_cmd( 0x10 | (0>>4) );
|
ssd1306_cmd( 0x10 | (SSD1306_OFFSET>>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);
|
||||||
|
|
@ -298,15 +312,18 @@ void ssd1306_drawImage(uint32_t x, uint32_t y, const unsigned char* input, uint3
|
||||||
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 * 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
|
||||||
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
|
buffer_addr = x_absolute + SSD1306_W * (y_absolute / 8);
|
||||||
// state of current pixel
|
// state of current pixel
|
||||||
uint8_t input_pixel = input_byte & (1 << pixel);
|
#ifdef SSD1306_BMP_LSB_FIRST
|
||||||
|
uint8_t input_pixel = input_byte & (1 << pixel); // LSB first
|
||||||
|
#else
|
||||||
|
uint8_t input_pixel = input_byte & (0x80 >> pixel); // MSB first (default)
|
||||||
|
#endif
|
||||||
switch (color_mode) {
|
switch (color_mode) {
|
||||||
case 0:
|
case 0:
|
||||||
// write pixels as they are
|
// write pixels as they are
|
||||||
|
|
@ -592,7 +609,7 @@ void ssd1306_drawchar(uint8_t x, uint8_t y, uint8_t chr, uint8_t color)
|
||||||
/*
|
/*
|
||||||
* draw a string to the display
|
* draw a string to the display
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawstr(uint8_t x, uint8_t y, char *str, uint8_t color)
|
void ssd1306_drawstr(int x, int y, const char *str, uint8_t color)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
|
|
@ -618,7 +635,7 @@ typedef enum {
|
||||||
/*
|
/*
|
||||||
* Draw character to the display buffer, scaled to size
|
* Draw character to the display buffer, scaled to size
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_size_t font_size)
|
void ssd1306_drawchar_sz(int x, int y, uint8_t chr, int color, font_size_t font_size)
|
||||||
{
|
{
|
||||||
uint16_t i, j, col;
|
uint16_t i, j, col;
|
||||||
uint8_t d;
|
uint8_t d;
|
||||||
|
|
@ -657,7 +674,7 @@ void ssd1306_drawchar_sz(uint8_t x, uint8_t y, uint8_t chr, uint8_t color, font_
|
||||||
/*
|
/*
|
||||||
* draw a string to the display buffer, scaled to size
|
* draw a string to the display buffer, scaled to size
|
||||||
*/
|
*/
|
||||||
void ssd1306_drawstr_sz(uint8_t x, uint8_t y, char *str, uint8_t color, font_size_t font_size)
|
void ssd1306_drawstr_sz(int x, int y, const char *str, uint8_t color, font_size_t font_size)
|
||||||
{
|
{
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,10 @@
|
||||||
#define SSD1306_SOFT_SPI 0
|
#define SSD1306_SOFT_SPI 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SSD1306_3WIRE_SPI
|
||||||
|
#define SSD1306_3WIRE_SPI 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* init SPI and GPIO for SSD1306 OLED
|
* init SPI and GPIO for SSD1306 OLED
|
||||||
*/
|
*/
|
||||||
|
|
@ -101,6 +105,10 @@ 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 SSD1306_3WIRE_SPI
|
||||||
|
uint8_t leftover = 0;
|
||||||
|
int8_t dc_pos = 7;
|
||||||
|
#else
|
||||||
if(cmd)
|
if(cmd)
|
||||||
{
|
{
|
||||||
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
funDigitalWrite( SSD1306_DC_PIN, FUN_LOW );
|
||||||
|
|
@ -109,7 +117,7 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
{
|
{
|
||||||
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
funDigitalWrite( SSD1306_DC_PIN, FUN_HIGH );
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
funDigitalWrite( SSD1306_CS_PIN, FUN_LOW );
|
||||||
|
|
||||||
// send data
|
// send data
|
||||||
|
|
@ -118,6 +126,11 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
#if SSD1306_SOFT_SPI
|
#if SSD1306_SOFT_SPI
|
||||||
uint8_t c = *data++;
|
uint8_t c = *data++;
|
||||||
int i = 8;
|
int i = 8;
|
||||||
|
#if SSD1306_3WIRE_SPI
|
||||||
|
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
|
||||||
|
funDigitalWrite( SSD1306_MOSI_PIN, !cmd ); ADD_N_NOPS(1)
|
||||||
|
funDigitalWrite( SSD1306_SCK_PIN, FUN_HIGH ); ADD_N_NOPS(1)
|
||||||
|
#endif
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
|
funDigitalWrite( SSD1306_SCK_PIN, FUN_LOW ); ADD_N_NOPS(1)
|
||||||
|
|
@ -128,15 +141,41 @@ uint8_t ssd1306_pkt_send(const uint8_t *data, int sz, uint8_t cmd)
|
||||||
|
|
||||||
#elif defined( CH5xx )
|
#elif defined( CH5xx )
|
||||||
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
||||||
|
#if SSD1306_3WIRE_SPI
|
||||||
|
uint8_t byte = leftover | (!cmd) << dc_pos | (*data) >> (8-dc_pos);
|
||||||
|
leftover = (*data++) << (dc_pos);
|
||||||
|
if( dc_pos-- < 0 ) dc_pos = 7;
|
||||||
|
R8_SPI0_BUFFER = byte;
|
||||||
|
#else
|
||||||
R8_SPI0_BUFFER = *data++;
|
R8_SPI0_BUFFER = *data++;
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
// wait for TXE
|
// wait for TXE
|
||||||
while(!(SPI1->STATR & SPI_STATR_TXE));
|
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||||
|
|
||||||
// Send byte
|
// Send byte
|
||||||
|
#if SSD1306_3WIRE_SPI
|
||||||
|
uint8_t byte = leftover | (!cmd) << dc_pos | (*data) >> (8-dc_pos);
|
||||||
|
leftover = (*data++) << (dc_pos--);
|
||||||
|
if( dc_pos < 0 ) dc_pos = 7;
|
||||||
|
SPI1->DATAR = byte;
|
||||||
|
#else
|
||||||
SPI1->DATAR = *data++;
|
SPI1->DATAR = *data++;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#if !SSD1306_SOFT_SPI && SSD1306_3WIRE_SPI
|
||||||
|
if( dc_pos )
|
||||||
|
{
|
||||||
|
#if defined( CH5xx )
|
||||||
|
while(! (R8_SPI0_INT_FLAG & RB_SPI_FREE) );
|
||||||
|
R8_SPI0_BUFFER = leftover;
|
||||||
|
#else
|
||||||
|
while(!(SPI1->STATR & SPI_STATR_TXE));
|
||||||
|
SPI1->DATAR = leftover;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// wait for not busy before exiting
|
// wait for not busy before exiting
|
||||||
#if SSD1306_SOFT_SPI
|
#if SSD1306_SOFT_SPI
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@
|
||||||
|
|
||||||
I2CPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigI2C
|
I2CPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigI2C
|
||||||
to be generated.
|
to be generated.
|
||||||
I2CNOSTATIC -> #define if you want the functions to be generated as
|
I2CCODE -> decorate functions with this, otherwise assume it's static.
|
||||||
not-static code.
|
|
||||||
|
|
||||||
NOTE: You must initially configure the port to be outputs on both DSDA
|
NOTE: You must initially configure the port to be outputs on both DSDA
|
||||||
and DSCL and set them both to be driven high.
|
and DSCL and set them both to be driven high.
|
||||||
|
|
@ -46,10 +45,8 @@
|
||||||
#define I2CPREFIX
|
#define I2CPREFIX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef I2CNOSTATIC
|
#ifndef I2CCODE
|
||||||
#define I2CSTATICODE
|
#define I2CCODE static
|
||||||
#else
|
|
||||||
#define I2CSTATICODE static
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef I2CFNCOLLAPSE
|
#ifndef I2CFNCOLLAPSE
|
||||||
|
|
@ -69,13 +66,13 @@
|
||||||
#define DSDA_IHIGH DSDA_INPUT
|
#define DSDA_IHIGH DSDA_INPUT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, ConfigI2C)()
|
I2CCODE void I2CFNCOLLAPSE(I2CPREFIX, ConfigI2C)()
|
||||||
{
|
{
|
||||||
DSDA_IHIGH
|
DSDA_IHIGH
|
||||||
DSCL_IHIGH
|
DSCL_IHIGH
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)()
|
I2CCODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)()
|
||||||
{
|
{
|
||||||
DELAY1
|
DELAY1
|
||||||
DSCL_IHIGH
|
DSCL_IHIGH
|
||||||
|
|
@ -86,7 +83,7 @@ I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)()
|
||||||
DELAY1
|
DELAY1
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)()
|
I2CCODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)()
|
||||||
{
|
{
|
||||||
DELAY1
|
DELAY1
|
||||||
DSDA_OUTPUT
|
DSDA_OUTPUT
|
||||||
|
|
@ -98,7 +95,7 @@ I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return nonzero on failure.
|
// Return nonzero on failure.
|
||||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data)
|
I2CCODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
// Assume we are in a started state (DSCL = 0 & DSDA = 0)
|
// Assume we are in a started state (DSCL = 0 & DSDA = 0)
|
||||||
|
|
@ -136,7 +133,7 @@ I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data
|
||||||
|
|
||||||
#if I2CNEEDGETBYTE
|
#if I2CNEEDGETBYTE
|
||||||
|
|
||||||
I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak)
|
I2CCODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak)
|
||||||
{
|
{
|
||||||
unsigned char i;
|
unsigned char i;
|
||||||
unsigned char ret = 0;
|
unsigned char ret = 0;
|
||||||
|
|
@ -179,7 +176,7 @@ I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak)
|
||||||
|
|
||||||
#if I2CNEEDSCAN
|
#if I2CNEEDSCAN
|
||||||
|
|
||||||
I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, Scan)()
|
I2CCODE void I2CFNCOLLAPSE(I2CPREFIX, Scan)()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
printf( " " );
|
printf( " " );
|
||||||
|
|
|
||||||
376
inc/extralibs/static_onewire.h
Normal file
376
inc/extralibs/static_onewire.h
Normal file
|
|
@ -0,0 +1,376 @@
|
||||||
|
/*
|
||||||
|
Copyright 2025 monte-monte
|
||||||
|
MIT license
|
||||||
|
|
||||||
|
Generic 1-wire library for any GPIO-based system.
|
||||||
|
|
||||||
|
WiP.
|
||||||
|
|
||||||
|
Include this in your .c file only!!!
|
||||||
|
Include it after the following are defined:
|
||||||
|
|
||||||
|
ONEPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigONE
|
||||||
|
to be generated.
|
||||||
|
ONENOSTATIC -> #define if you want the functions to be generated as
|
||||||
|
not-static code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Put this in your code:
|
||||||
|
|
||||||
|
#define DELAY(n) Delay_Us(n)
|
||||||
|
#define ONE_INPUT { funPinMode(PIN_ONE, GPIO_CFGLR_IN_PUPD); funDigitalWrite(PIN_ONE, 1); }
|
||||||
|
#define ONE_OUTPUT { funDigitalWrite(PIN_ONE, 0); funPinMode(PIN_ONE, GPIO_CFGLR_OUT_2Mhz_PP); }
|
||||||
|
#define ONE_SET { funDigitalWrite(PIN_ONE, 1); }
|
||||||
|
#define ONE_CLEAR { funDigitalWrite(PIN_ONE, 0); }
|
||||||
|
#define ONE_READ { funDigitalRead(PIN_ONE); }
|
||||||
|
|
||||||
|
#define ONENEEDSCAN 1
|
||||||
|
#define ONENEEDCRC8_TABLE 1
|
||||||
|
#define __ONE_TABLE_IN_FLASH __attribute__((section(".srodata"), used))
|
||||||
|
|
||||||
|
#include "static_onewire.h"
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
unsigned char rom[8];
|
||||||
|
struct {
|
||||||
|
unsigned char code;
|
||||||
|
unsigned char serial[6];
|
||||||
|
unsigned char crc;
|
||||||
|
};
|
||||||
|
} __attribute__((packed)) OneWire_dev_t;
|
||||||
|
|
||||||
|
#define ONEDELAY_A DELAY(6) // (3)
|
||||||
|
#define ONEDELAY_B DELAY(64) // (55)
|
||||||
|
#define ONEDELAY_C DELAY(60) // (65)
|
||||||
|
#define ONEDELAY_D DELAY(10) // (5)
|
||||||
|
#define ONEDELAY_E DELAY(9) // (10)
|
||||||
|
#define ONEDELAY_F DELAY(55) // (53)
|
||||||
|
#define ONEDELAY_G
|
||||||
|
#define ONEDELAY_H DELAY(480)
|
||||||
|
#define ONEDELAY_I DELAY(70)
|
||||||
|
#define ONEDELAY_J DELAY(410)
|
||||||
|
|
||||||
|
#ifndef INTERRUPT_OFF
|
||||||
|
#define INTERRUPT_OFF __disable_irq()
|
||||||
|
#endif
|
||||||
|
#ifndef INTERRUPT_ON
|
||||||
|
#define INTERRUPT_ON __enable_irq()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ONEWIRE_SEARCH_ROM_CMD 0xF0
|
||||||
|
#define ONEWIRE_COND_SEARCH_ROM_CMD 0xEC
|
||||||
|
#define ONEWIRE_READ_ROM_CMD 0x33
|
||||||
|
#define ONEWIRE_SELECT_CMD 0x55
|
||||||
|
#define ONEWIRE_SKIP_CMD 0xCC
|
||||||
|
|
||||||
|
#ifndef ONEPREFIX
|
||||||
|
#define ONEPREFIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ONENOSTATIC
|
||||||
|
#define ONESTATICODE
|
||||||
|
#else
|
||||||
|
#define ONESTATICODE static
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ONEFNCOLLAPSE
|
||||||
|
#define INTONEFNCOLLAPSE(PFX, name) PFX##name
|
||||||
|
#define ONEFNCOLLAPSE(PFX, name) INTONEFNCOLLAPSE(PFX, name)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ONENEEDGETBYTE
|
||||||
|
#define ONENEEDGETBYTE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __ONE_TABLE_IN_FLASH
|
||||||
|
#define __ONE_TABLE_IN_FLASH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ONE_CRC_POLYNOMIAL
|
||||||
|
#define ONE_CRC_POLYNOMIAL 0x8C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ONESTATICODE unsigned int ONEFNCOLLAPSE(ONEPREFIX, Reset)() {
|
||||||
|
unsigned int state;
|
||||||
|
unsigned char retries = 125;
|
||||||
|
ONE_INPUT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
DELAY(2);
|
||||||
|
} while(!ONE_READ && --retries);
|
||||||
|
|
||||||
|
INTERRUPT_OFF;
|
||||||
|
ONE_OUTPUT;
|
||||||
|
ONE_CLEAR;
|
||||||
|
ONEDELAY_H;
|
||||||
|
// ONE_SET;
|
||||||
|
ONE_INPUT;
|
||||||
|
ONEDELAY_I;
|
||||||
|
|
||||||
|
state = ONE_READ;
|
||||||
|
ONEDELAY_J;
|
||||||
|
INTERRUPT_ON;
|
||||||
|
// ONE_OUTPUT;
|
||||||
|
|
||||||
|
return !!state;
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE void ONEFNCOLLAPSE(ONEPREFIX, SendBit)(const unsigned char bit) {
|
||||||
|
ONE_OUTPUT;
|
||||||
|
ONE_CLEAR;
|
||||||
|
|
||||||
|
INTERRUPT_OFF;
|
||||||
|
if (bit) ONEDELAY_A;
|
||||||
|
else ONEDELAY_C;
|
||||||
|
// if (bit) DELAY(10);
|
||||||
|
// else DELAY(65);
|
||||||
|
|
||||||
|
ONE_SET;
|
||||||
|
|
||||||
|
if (bit) ONEDELAY_B;
|
||||||
|
else ONEDELAY_D;
|
||||||
|
INTERRUPT_ON;
|
||||||
|
// if (bit) DELAY(55);
|
||||||
|
// else DELAY(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE void ONEFNCOLLAPSE(ONEPREFIX, SendByte)(const unsigned char data) {
|
||||||
|
for (unsigned char i = 1; i != 0; i <<= 1) {
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendBit)(data & i);
|
||||||
|
}
|
||||||
|
// ONE_CLEAR; // This makes reads unreliable on my knock-offs of db18b20
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE unsigned char ONEFNCOLLAPSE(ONEPREFIX, GetBit)() {
|
||||||
|
unsigned char ret = 0;
|
||||||
|
|
||||||
|
INTERRUPT_OFF;
|
||||||
|
ONE_OUTPUT;
|
||||||
|
ONE_CLEAR;
|
||||||
|
ONEDELAY_A;
|
||||||
|
ONE_INPUT;
|
||||||
|
ONEDELAY_E;
|
||||||
|
|
||||||
|
ret = (ONE_READ);
|
||||||
|
ONEDELAY_F;
|
||||||
|
INTERRUPT_ON;
|
||||||
|
|
||||||
|
// ONE_OUTPUT;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE unsigned char ONEFNCOLLAPSE(ONEPREFIX, GetByte)() {
|
||||||
|
unsigned char ret = 0;
|
||||||
|
|
||||||
|
for (unsigned char i = 0; i < 8; i++) {
|
||||||
|
ret |= ONEFNCOLLAPSE(ONEPREFIX, GetBit)() << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE void ONEFNCOLLAPSE(ONEPREFIX, Select)(OneWire_dev_t device) {
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendByte)(ONEWIRE_SELECT_CMD);
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendByte)(device.rom[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ONESTATICODE void ONEFNCOLLAPSE(ONEPREFIX, PowerOff)() {
|
||||||
|
ONE_INPUT;
|
||||||
|
ONE_CLEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ONENEEDREADROM
|
||||||
|
|
||||||
|
ONESTATICODE char ONEFNCOLLAPSE(ONEPREFIX, ReadRom)(OneWire_dev_t * dev) {
|
||||||
|
|
||||||
|
if (!dev) return -1;
|
||||||
|
|
||||||
|
uint8_t * ptr = (uint8_t*)dev;
|
||||||
|
|
||||||
|
if (ONEFNCOLLAPSE(ONEPREFIX, Reset)()) return -2;
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendByte)(ONEWIRE_READ_ROM_CMD);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(OneWire_dev_t); i++) {
|
||||||
|
*(ptr++) = ONEFNCOLLAPSE(ONEPREFIX, GetByte)();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ONENEEDCRC8_TABLE
|
||||||
|
// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0
|
||||||
|
// Tiny 32 bytes CRC table. Copyright (C) 1992-2017 Arjen Lentz
|
||||||
|
// http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table
|
||||||
|
__ONE_TABLE_IN_FLASH
|
||||||
|
const unsigned char crc8_table[] = {
|
||||||
|
0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83,
|
||||||
|
0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41,
|
||||||
|
0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8,
|
||||||
|
0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74
|
||||||
|
};
|
||||||
|
|
||||||
|
ONESTATICODE unsigned char ONEFNCOLLAPSE(ONEPREFIX, CRC8)(unsigned char crc, unsigned char * bytes, unsigned char size) {
|
||||||
|
|
||||||
|
while (size--) {
|
||||||
|
crc = *bytes++ ^ crc; // just re-using crc as intermediate
|
||||||
|
crc = crc8_table[crc & 0x0f] ^ crc8_table[16 + ((crc >> 4) & 0x0f)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
#elif ONENEEDCRC8
|
||||||
|
// Following functions were written by M. P. Hayes for https://github.com/mph-/mmculib/
|
||||||
|
|
||||||
|
// Update CRC for a single byte.
|
||||||
|
ONESTATICODE unsigned char ONEFNCOLLAPSE(ONEPREFIX, CRC8_byte)(unsigned char crc, unsigned char val) {
|
||||||
|
|
||||||
|
crc = crc ^ val;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (crc & 0x01)
|
||||||
|
crc = (crc >> 1) ^ 0x8C;
|
||||||
|
else
|
||||||
|
crc >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update CRC for a number of bytes.
|
||||||
|
ONESTATICODE unsigned char ONEFNCOLLAPSE(ONEPREFIX, CRC8)(unsigned char crc, unsigned char * bytes, unsigned char size) {
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
crc = ONEFNCOLLAPSE(ONEPREFIX, CRC8_byte)(crc, bytes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ONENEEDCRC16
|
||||||
|
// Following function is taken from crcutil.c of Public Domain 1-Wire Net Functions
|
||||||
|
// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
__ONE_TABLE_IN_FLASH
|
||||||
|
static const char oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 };
|
||||||
|
|
||||||
|
ONESTATICODE unsigned short ONEFNCOLLAPSE(ONEPREFIX, CRC16)(unsigned short crc, unsigned char * bytes, unsigned char size) {
|
||||||
|
for (int i = 0 ; i < len ; i++) {
|
||||||
|
// Even though we're just copying a byte from the input,
|
||||||
|
// we'll be doing 16-bit computation with it.
|
||||||
|
unsigned short cdata = input[i];
|
||||||
|
cdata = (cdata ^ crc) & 0xff;
|
||||||
|
crc >>= 8;
|
||||||
|
|
||||||
|
if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) crc ^= 0xC001;
|
||||||
|
|
||||||
|
cdata <<= 6;
|
||||||
|
crc ^= cdata;
|
||||||
|
cdata <<= 1;
|
||||||
|
crc ^= cdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ONENEEDSCAN
|
||||||
|
|
||||||
|
// As described here https://www.analog.com/en/resources/app-notes/1wire-search-algorithm.html
|
||||||
|
ONESTATICODE int ONEFNCOLLAPSE(ONEPREFIX, Scan)(OneWire_dev_t * dev_buffer, unsigned char size) {
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
|
unsigned char retries = 10;
|
||||||
|
|
||||||
|
unsigned char bit = 0;
|
||||||
|
unsigned char bit_comp = 0;
|
||||||
|
unsigned char direction = 0;
|
||||||
|
unsigned char discrepancy = 0;
|
||||||
|
|
||||||
|
// unsigned char family_discrepancy = 0;
|
||||||
|
unsigned char last_zero = 0;
|
||||||
|
|
||||||
|
unsigned char bit_n = 1;
|
||||||
|
unsigned char byte_mask = 1;
|
||||||
|
unsigned char byte_n = 0;
|
||||||
|
|
||||||
|
unsigned char device_n = 0;
|
||||||
|
|
||||||
|
search_start:
|
||||||
|
|
||||||
|
if ((ret = ONEFNCOLLAPSE(ONEPREFIX, Reset)())) goto search_end;
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendByte)(ONEWIRE_SEARCH_ROM_CMD);
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
bit = ONEFNCOLLAPSE(ONEPREFIX, GetBit)();
|
||||||
|
bit_comp = ONEFNCOLLAPSE(ONEPREFIX, GetBit)();
|
||||||
|
|
||||||
|
if (bit && bit_comp) break; // 1 1 - No more devices on the bus
|
||||||
|
|
||||||
|
if (bit == bit_comp) { // 0 0 - Discrepancy
|
||||||
|
if (bit_n == discrepancy) {
|
||||||
|
direction = 1;
|
||||||
|
} else {
|
||||||
|
if (bit_n > discrepancy) direction = 0;
|
||||||
|
else direction = !!(dev_buffer[device_n?device_n-1:0].rom[byte_n] & byte_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!direction) {
|
||||||
|
last_zero = bit_n;
|
||||||
|
// if (last_zero < 9) family_discrepancy = last_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
direction = bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction) dev_buffer[device_n].rom[byte_n] |= byte_mask;
|
||||||
|
else dev_buffer[device_n].rom[byte_n] &= ~byte_mask;
|
||||||
|
|
||||||
|
bit_n++;
|
||||||
|
if (!(byte_mask <<= 1)) {
|
||||||
|
byte_mask = 1;
|
||||||
|
byte_n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ONEFNCOLLAPSE(ONEPREFIX, SendBit)(direction);
|
||||||
|
} while(byte_n < 8);
|
||||||
|
|
||||||
|
#if (ONENEEDCRC8) || (ONENEEDCRC8_TABLE)
|
||||||
|
if (dev_buffer[device_n].crc != ONEFNCOLLAPSE(ONEPREFIX, CRC8)(0, dev_buffer[device_n].rom, 7)) {
|
||||||
|
if (--retries) goto search_start;
|
||||||
|
else retries = 10;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((++device_n < size) && last_zero) {
|
||||||
|
discrepancy = last_zero;
|
||||||
|
last_zero = 0;
|
||||||
|
bit_n = 1;
|
||||||
|
byte_n = 0;
|
||||||
|
direction = 0;
|
||||||
|
goto search_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
search_end:
|
||||||
|
if (device_n) return device_n;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
857
inc/extralibs/usbd.c
Normal file
857
inc/extralibs/usbd.c
Normal file
|
|
@ -0,0 +1,857 @@
|
||||||
|
#include "usbd.h"
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "usb_config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define ANYPRINTF (defined( FUNCONF_USE_DEBUGPRINTF ) && FUNCONF_USE_DEBUGPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_UARTPRINTF ) && FUNCONF_USE_UARTPRINTF) || \
|
||||||
|
(defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF)
|
||||||
|
|
||||||
|
volatile uint8_t usb_debug = 0;
|
||||||
|
// Uncomment to enable debugging
|
||||||
|
// #define DEBUG
|
||||||
|
#define USBD_DEBUGPRINTF( ... ) {if ( usb_debug ) { printf( __VA_ARGS__ ); }}
|
||||||
|
#define min(a, b) (((a)<(b))?(a):(b))
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
struct _USBState USBDCTX;
|
||||||
|
|
||||||
|
void USBD_InternalFinishSetup();
|
||||||
|
|
||||||
|
static inline void SetEPR_Status( const int ep, const uint16_t mask, const uint16_t value )
|
||||||
|
{
|
||||||
|
const uint16_t reg = USBD->EPR[ep];
|
||||||
|
const uint16_t current_stat = reg & mask;
|
||||||
|
// Which bits we need to toggle
|
||||||
|
const uint16_t toggle = current_stat ^ value;
|
||||||
|
|
||||||
|
// Conserve EA, TYPE and KIND (Non-toggle)
|
||||||
|
uint16_t write_val = ( reg & ( USBD_EPR_EA | USBD_EPR_EP_TYPE_MASK | USBD_EPR_EP_KIND ) );
|
||||||
|
write_val |= toggle;
|
||||||
|
// Write 1 has no effect for CTR_RX and CTR_TX (0 clears)
|
||||||
|
write_val |= ( USBD_EPR_CTR_RX | USBD_EPR_CTR_TX );
|
||||||
|
|
||||||
|
USBD->EPR[ep] = write_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int USBDSetup( void )
|
||||||
|
{
|
||||||
|
// Initialize USB pins to pull-down to avoid mis-detection
|
||||||
|
GPIOA->CFGHR &= ~( ( 0xf << ( 4 * 3 ) ) | ( 0xf << ( 4 * 4 ) ) );
|
||||||
|
GPIOA->CFGHR |= ( GPIO_Speed_2MHz | GPIO_CNF_OUT_PP ) << ( 4 * 3 ) | ( GPIO_Speed_2MHz | GPIO_CNF_OUT_PP )
|
||||||
|
<< ( 4 * 4 );
|
||||||
|
GPIOA->BSHR = ( 1 << ( 16 + 11 ) ) | ( 1 << ( 16 + 12 ) );
|
||||||
|
|
||||||
|
// We need 48MHz clock for USB
|
||||||
|
#if FUNCONF_SYSTEM_CORE_CLOCK == 240000000
|
||||||
|
RCC->CFGR0 = ( RCC->CFGR0 & ~RCC_USBPRE ) | RCC_USBPRE_DIV5;
|
||||||
|
#elif FUNCONF_SYSTEM_CORE_CLOCK == 144000000
|
||||||
|
RCC->CFGR0 = ( RCC->CFGR0 & ~RCC_USBPRE ) | RCC_USBPRE_DIV3;
|
||||||
|
#elif FUNCONF_SYSTEM_CORE_CLOCK == 96000000
|
||||||
|
RCC->CFGR0 = ( RCC->CFGR0 & ~RCC_USBPRE ) | RCC_USBPRE_DIV2;
|
||||||
|
#elif FUNCONF_SYSTEM_CORE_CLOCK == 48000000
|
||||||
|
RCC->CFGR0 = ( RCC->CFGR0 & ~RCC_USBPRE ) | RCC_USBPRE_DIV1;
|
||||||
|
#else
|
||||||
|
#error CH32V20x/30x need 240/144/96/48MHz main clock for USB to work
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RCC->APB2PCENR |= RCC_AFIOEN | RCC_IOPAEN;
|
||||||
|
RCC->AHBPCENR = RCC_AHBPeriph_SRAM;
|
||||||
|
RCC->APB1PCENR |= RCC_USBEN;
|
||||||
|
|
||||||
|
#if defined( CH32V203F8 ) || defined( CH32V203F8U6 )
|
||||||
|
// Sometimes USB shares pins w/ SWD
|
||||||
|
// SWD must be disabled in such cases
|
||||||
|
Delay_Ms( 100 );
|
||||||
|
AFIO->PCFR1 |= AFIO_PCFR1_SWJ_CFG_DISABLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Suspend & disable all interrupts
|
||||||
|
USBD->CNTR = USBD_FRES;
|
||||||
|
USBD->CNTR = 0;
|
||||||
|
|
||||||
|
// Delay a tad (Slightly more optimized)
|
||||||
|
for ( volatile int i = 0; i < 1000; i++ );
|
||||||
|
|
||||||
|
// Initialize required registers & packet buffer description table
|
||||||
|
USBD_InternalFinishSetup();
|
||||||
|
|
||||||
|
EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
|
||||||
|
USBD->CNTR = USBD_CTRM | USBD_RESETM | USBD_SUSPM | USBD_WKUPM;
|
||||||
|
USBD->ISTR = 0;
|
||||||
|
NVIC_EnableIRQ( USB_LP_CAN1_RX0_IRQn );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WEAK void USBD_InternalFinishSetup( void )
|
||||||
|
{
|
||||||
|
USBD->BTABLE = 0;
|
||||||
|
|
||||||
|
// EP0 has to be RTX for control transfers
|
||||||
|
USBDCTX.endpoints[0].mode = USBD_EP_MODE_RX | USBD_EP_MODE_TX;
|
||||||
|
|
||||||
|
#if FUSB_EP1_MODE
|
||||||
|
USBDCTX.endpoints[1].mode = FUSB_EP1_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP2_MODE
|
||||||
|
USBDCTX.endpoints[2].mode = FUSB_EP2_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP3_MODE
|
||||||
|
USBDCTX.endpoints[3].mode = FUSB_EP3_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP4_MODE
|
||||||
|
USBDCTX.endpoints[4].mode = FUSB_EP4_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP5_MODE
|
||||||
|
USBDCTX.endpoints[5].mode = FUSB_EP5_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP6_MODE
|
||||||
|
USBDCTX.endpoints[6].mode = FUSB_EP6_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_EP7_MODE
|
||||||
|
USBDCTX.endpoints[7].mode = FUSB_EP7_MODE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 64 bytes for each buffer
|
||||||
|
uint16_t pma = USBD_PMA_BASE; // running allocation cursor
|
||||||
|
for ( uint8_t ep = 0; ep < FUSB_MAX_EP_CNT; ++ep )
|
||||||
|
{
|
||||||
|
USBDCTX.usbd_ep_data_ptr[ep] = (uint32_t *)( CAN_USBD_SHARED_BASE + pma * 2 );
|
||||||
|
|
||||||
|
if ( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_TX )
|
||||||
|
{
|
||||||
|
USBD_BDT->EP[ep].ADDn_TX = pma;
|
||||||
|
// Configured on the fly
|
||||||
|
USBD_BDT->EP[ep].COUNTn_TX = 0;
|
||||||
|
|
||||||
|
// If we have an RX node, we double-buffer
|
||||||
|
if ( !( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_RX ) )
|
||||||
|
{
|
||||||
|
pma += USBD_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_RX )
|
||||||
|
{
|
||||||
|
USBD_BDT->EP[ep].ADDn_RX = pma;
|
||||||
|
// USBD_BLSIZE: Each cnt is 32 bytes
|
||||||
|
USBD_BDT->EP[ep].COUNTn_RX = USBD_BLSIZE | ( ( USBD_PACKET_SIZE / 32 - 1 ) << 10 );
|
||||||
|
pma += USBD_PACKET_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBDReset( void )
|
||||||
|
{
|
||||||
|
NVIC_DisableIRQ( USB_LP_CAN1_RX0_IRQn );
|
||||||
|
USBD->CNTR = USBD_FRES;
|
||||||
|
for ( volatile int i = 0; i < 1000; i++ );
|
||||||
|
USBD->CNTR = USBD_CTRM | USBD_RESETM | USBD_SUSPM | USBD_WKUPM;
|
||||||
|
USBD->ISTR = 0;
|
||||||
|
// Delay 100us for the USB to fully reset
|
||||||
|
// Not recognized otherwise
|
||||||
|
Delay_Us( 100 );
|
||||||
|
NVIC_EnableIRQ( USB_LP_CAN1_RX0_IRQn );
|
||||||
|
}
|
||||||
|
|
||||||
|
// It seems that even WCH doesn't use the high-priority usb interrupt
|
||||||
|
// maybe it's only for CAN?
|
||||||
|
#if FUSB_USE_HPE
|
||||||
|
// There is an issue with some registers apparently getting lost with HPE, just do it the slow way.
|
||||||
|
void USB_LP_CAN1_RX0_IRQHandler( void ) __attribute__( ( section( ".text.vector_handler" ) ) )
|
||||||
|
__attribute( ( interrupt ) );
|
||||||
|
#else
|
||||||
|
#if defined( FUSB_FROM_RAM ) && ( FUSB_FROM_RAM )
|
||||||
|
void USB_LP_CAN1_RX0_IRQHandler( void ) __USBFS_FUN_ATTRIBUTE __attribute( ( interrupt ) );
|
||||||
|
#else
|
||||||
|
void USB_LP_CAN1_RX0_IRQHandler( void ) __attribute__( ( section( ".text.vector_handler" ) ) )
|
||||||
|
__attribute( ( interrupt ) );
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void USB_LP_CAN1_RX0_IRQHandler( void )
|
||||||
|
{
|
||||||
|
static uint8_t zeros[] = { 0, 0 }; // Macro to reply 0s
|
||||||
|
const uint32_t istr = USBD->ISTR;
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
// Correct transfer
|
||||||
|
if ( istr & USBD_CTR )
|
||||||
|
{
|
||||||
|
const int ep = istr & USBD_EP_ID;
|
||||||
|
const int epr = USBD->EPR[ep];
|
||||||
|
|
||||||
|
#ifdef USB_DEBUG
|
||||||
|
if ( epr & USBD_CTR_RX && epr & USBD_CTR_TX )
|
||||||
|
{
|
||||||
|
printf( "Both RX & TX flags are set! Processing is too slow\n" );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( epr & USBD_CTR_RX )
|
||||||
|
{
|
||||||
|
// EP0 Setup Packet
|
||||||
|
if ( ep == 0 && epr & USBD_SETUP )
|
||||||
|
{
|
||||||
|
// Memory in USBD is stored in ranks of 16 bits (even though they can store
|
||||||
|
// 32 bits)
|
||||||
|
// What a weird design
|
||||||
|
const uint8_t USBD_request_type = USBDCTX.USBD_SetupReqType = USBDCTX.usbd_ep_data_ptr[0][0] & 0xFF;
|
||||||
|
const uint8_t USBD_request = USBDCTX.USBD_SetupReqCode = USBDCTX.usbd_ep_data_ptr[0][0] >> 8;
|
||||||
|
const uint32_t USBD_index = ( (uint32_t)USBDCTX.usbd_ep_data_ptr[0][2] );
|
||||||
|
const uint32_t USBD_indexValue = USBDCTX.USBD_IndexValue =
|
||||||
|
( ( (uint32_t)( USBDCTX.usbd_ep_data_ptr[0][2] ) ) << 16 ) | USBDCTX.usbd_ep_data_ptr[0][1];
|
||||||
|
const uint16_t USBD_length = USBDCTX.USBD_SetupReqLen = USBDCTX.usbd_ep_data_ptr[0][3];
|
||||||
|
|
||||||
|
// Copy to CTRL0BUFF
|
||||||
|
// Can be removed if CTRL0BUFF unused
|
||||||
|
for ( int i = 0; i < min( USBD_length, 64 ); ++i )
|
||||||
|
{
|
||||||
|
CTRL0BUFF[i] = ( USBDCTX.usbd_ep_data_ptr[0][i / 2] >> ( ( i & 1 ) << 3 ) ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request 0b00100001 0x0A = SET IDLE, can be ignored
|
||||||
|
if ( ( USBD_request_type & USBD_REQ_TYP_MASK ) == USBD_REQ_TYP_STANDARD )
|
||||||
|
{
|
||||||
|
// Standard setup
|
||||||
|
switch ( USBD_request )
|
||||||
|
{
|
||||||
|
case USB_GET_STATUS:
|
||||||
|
// Non remote wakeup and non self powered -> 0
|
||||||
|
USBDCTX.pCtrlPayloadPtr = zeros;
|
||||||
|
USBDCTX.USBD_SetupReqLen = 2;
|
||||||
|
break;
|
||||||
|
case USB_SET_ADDRESS:
|
||||||
|
USBDCTX.USBD_DevAddr = USBD_indexValue & 0xFF;
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
break;
|
||||||
|
case USB_GET_DESCRIPTOR:
|
||||||
|
const struct descriptor_list_struct *e = descriptor_list;
|
||||||
|
const struct descriptor_list_struct *e_end = e + DESCRIPTOR_LIST_ENTRIES;
|
||||||
|
for ( ; e != e_end; e++ )
|
||||||
|
{
|
||||||
|
if ( e->lIndexValue == (uint32_t)USBD_indexValue )
|
||||||
|
{
|
||||||
|
USBDCTX.pCtrlPayloadPtr = (uint8_t *)e->addr;
|
||||||
|
USBDCTX.USBD_SetupReqLen = min( e->length, USBD_length );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( e == e_end ) goto stall;
|
||||||
|
break;
|
||||||
|
case USB_GET_CONFIG:
|
||||||
|
USBDCTX.pCtrlPayloadPtr = &USBDCTX.USBD_DevConfig;
|
||||||
|
USBDCTX.USBD_SetupReqLen = 1;
|
||||||
|
break;
|
||||||
|
case USB_SET_CONFIG:
|
||||||
|
USBDCTX.USBD_DevConfig = USBD_indexValue & 0xFF;
|
||||||
|
USBDCTX.USBD_DevEnumStatus = 0x01;
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
|
||||||
|
// Reset DTOG bits
|
||||||
|
for ( int ep = 1; ep < FUSB_MAX_EP_CNT; ep++ )
|
||||||
|
{
|
||||||
|
if ( USBD->EPR[ep] & USBD_DTOG_RX )
|
||||||
|
{
|
||||||
|
USBD->EPR[ep] = ( USBD->EPR[ep] & ( USBD_EA | USBD_EPKIND | USBD_EPTYPE ) ) |
|
||||||
|
USBD_CTR_TX | USBD_CTR_RX | USBD_DTOG_RX;
|
||||||
|
}
|
||||||
|
if ( USBD->EPR[ep] & USBD_DTOG_TX )
|
||||||
|
{
|
||||||
|
USBD->EPR[ep] = ( USBD->EPR[ep] & ( USBD_EA | USBD_EPKIND | USBD_EPTYPE ) ) |
|
||||||
|
USBD_CTR_TX | USBD_CTR_RX | USBD_DTOG_TX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_GET_INTERFACE:
|
||||||
|
USBDCTX.pCtrlPayloadPtr = zeros;
|
||||||
|
USBDCTX.USBD_SetupReqLen = 1;
|
||||||
|
break;
|
||||||
|
case USB_CLEAR_FEATURE:
|
||||||
|
#if FUSB_SUPPORTS_SLEEP
|
||||||
|
if ( ( USBD_request_type & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
|
||||||
|
{
|
||||||
|
/* clear one device feature */
|
||||||
|
if ( (uint8_t)( USBD_indexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
|
||||||
|
{
|
||||||
|
/* clear usb sleep status, device not prepare to sleep */
|
||||||
|
USBDCTX.USBD_DevSleepStatus &= ~0x01;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if ( ( USBD_request_type & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
||||||
|
{
|
||||||
|
if ( (uint8_t)( USBD_indexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
||||||
|
{
|
||||||
|
/* Clear End-point Feature */
|
||||||
|
if ( USBDCTX.endpoints[ep].mode )
|
||||||
|
{
|
||||||
|
if ( USBD_index & DEF_UEP_IN &&
|
||||||
|
( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_TX ) )
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_NAK );
|
||||||
|
else if ( USBD_index & DEF_UEP_OUT &&
|
||||||
|
( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_RX ) )
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_ACK );
|
||||||
|
else
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case USB_SET_FEATURE:
|
||||||
|
if ( ( USBD_request_type & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )
|
||||||
|
{
|
||||||
|
#if FUSB_SUPPORTS_SLEEP
|
||||||
|
/* Set Device Feature */
|
||||||
|
if ( (uint8_t)( USBD_indexValue & 0xFF ) == USB_REQ_FEAT_REMOTE_WAKEUP )
|
||||||
|
{
|
||||||
|
/* Set Wake-up flag, device prepare to sleep */
|
||||||
|
USBD_DevSleepStatus |= 0x01;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( ( USBD_request_type & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
|
||||||
|
{
|
||||||
|
/* Set Endpoint Feature */
|
||||||
|
if ( (uint8_t)( USBD_indexValue & 0xFF ) == USB_REQ_FEAT_ENDP_HALT )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.endpoints[ep].mode )
|
||||||
|
{
|
||||||
|
if ( ( USBD_index & DEF_UEP_IN ) &&
|
||||||
|
( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_TX ) )
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_STALL );
|
||||||
|
else if ( ( USBD_index & DEF_UEP_OUT ) &&
|
||||||
|
( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_RX ) )
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_STALL );
|
||||||
|
else
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto stall;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: goto stall;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// EP0 Setup non-standard
|
||||||
|
#if FUSB_HID_INTERFACES > 0 || FUSB_USER_HANDLERS
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
|
const uint16_t packet_len = USBD_BDT->EP[ep].COUNTn_RX & 0x3FF;
|
||||||
|
uint8_t buff[USBD_PACKET_SIZE];
|
||||||
|
|
||||||
|
for ( int i = 0; i < packet_len; ++i )
|
||||||
|
{
|
||||||
|
buff[i] = ( USBDCTX.usbd_ep_data_ptr[ep][i / 2] >> ( ( i & 1 ) << 3 ) ) & 0xFF;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
switch ( USBD_request )
|
||||||
|
{
|
||||||
|
#if FUSB_HID_INTERFACES > 0
|
||||||
|
case HID_SET_REPORT:
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
|
len = HandleHidUserSetReportSetup( &USBDCTX, (tusb_control_request_t *)buff );
|
||||||
|
if ( len < 0 ) goto stall;
|
||||||
|
USBDCTX.USBD_SetupReqLen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_GET_REPORT:
|
||||||
|
len = HandleHidUserGetReportSetup( &USBDCTX, (tusb_control_request_t *)buff );
|
||||||
|
if ( len < 0 ) goto stall;
|
||||||
|
if ( len == 0 )
|
||||||
|
{
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// len > 0:
|
||||||
|
// We would like to send something it seems
|
||||||
|
USBDCTX.USBD_SetupReqLen = len;
|
||||||
|
len = min( USBD_PACKET_SIZE, len );
|
||||||
|
|
||||||
|
// If HandleHidUserGetReportSetup hasn't provided data to send,
|
||||||
|
// we ask HandleHidUserReportDataIn for data
|
||||||
|
if ( !USBDCTX.pCtrlPayloadPtr )
|
||||||
|
{
|
||||||
|
len = HandleHidUserReportDataIn( &USBDCTX, buff, len );
|
||||||
|
USBDCTX.pCtrlPayloadPtr = buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case HID_SET_IDLE:
|
||||||
|
if ( USBD_index < FUSB_HID_INTERFACES )
|
||||||
|
USBDCTX.USBD_HidIdle[USBD_index] = (uint8_t)( USBD_indexValue >> 8 );
|
||||||
|
|
||||||
|
// ACK
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
break;
|
||||||
|
case HID_SET_PROTOCOL:
|
||||||
|
if ( USBD_index < FUSB_HID_INTERFACES )
|
||||||
|
USBDCTX.USBD_HidProtocol[USBD_index] = (uint8_t)USBD_indexValue;
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
break;
|
||||||
|
case HID_GET_IDLE:
|
||||||
|
if ( USBD_index < FUSB_HID_INTERFACES )
|
||||||
|
{
|
||||||
|
USBDCTX.pCtrlPayloadPtr = &USBDCTX.USBD_HidIdle[USBD_index];
|
||||||
|
USBDCTX.USBD_SetupReqLen = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HID_GET_PROTOCOL:
|
||||||
|
if ( USBD_index < FUSB_HID_INTERFACES )
|
||||||
|
{
|
||||||
|
USBDCTX.pCtrlPayloadPtr = &USBDCTX.USBD_HidProtocol[USBD_index];
|
||||||
|
USBDCTX.USBD_SetupReqLen = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
#if FUSB_USER_HANDLERS
|
||||||
|
len = HandleSetupCustom( &USBDCTX, USBD_request );
|
||||||
|
|
||||||
|
if ( len )
|
||||||
|
{
|
||||||
|
if ( len < 0 )
|
||||||
|
{
|
||||||
|
// ACK
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
USBDCTX.USBD_SetupReqLen = min( len, USBD_length );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
goto stall;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// OUT RX packet
|
||||||
|
const uint16_t packet_len = USBD_BDT->EP[ep].COUNTn_RX & 0x3FF;
|
||||||
|
|
||||||
|
#if FUSB_HID_USER_REPORTS || FUSB_USER_HANDLERS
|
||||||
|
uint8_t buff[USBD_PACKET_SIZE];
|
||||||
|
|
||||||
|
for ( int i = 0; i < packet_len; ++i )
|
||||||
|
{
|
||||||
|
buff[i] = ( USBDCTX.usbd_ep_data_ptr[ep][i / 2] >> ( ( i & 1 ) << 3 ) ) & 0xFF;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
|
if ( USBDCTX.USBD_SetupReqCode == HID_SET_REPORT )
|
||||||
|
{
|
||||||
|
HandleHidUserReportDataOut( &USBDCTX, buff, len );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if FUSB_USER_HANDLERS
|
||||||
|
if ( USBDCTX.USBD_SetupReqCode != HID_SET_REPORT )
|
||||||
|
{
|
||||||
|
HandleDataOut( &USBDCTX, ep, buff, packet_len );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
|
// Transaction finished
|
||||||
|
if ( USBDCTX.USBD_SetupReqLen == 0 )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.USBD_SetupReqCode == HID_SET_REPORT ) HandleHidUserReportOutComplete( &USBDCTX );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( ep == 0 && ( USBDCTX.USBD_SetupReqLen == 0 || packet_len != 0 ) )
|
||||||
|
{
|
||||||
|
USBDCTX.USBD_SetupReqLen = USBD_SEND_ACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_ACK );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear RX (Toggle, 1 conserves bit)
|
||||||
|
USBD->EPR[ep] = ( USBD->EPR[ep] & ( USBD_EA | USBD_EPKIND | USBD_EPTYPE ) ) | USBD_CTR_TX;
|
||||||
|
}
|
||||||
|
|
||||||
|
// length < sizeof -> Return start
|
||||||
|
// length = sizeof -> Return all
|
||||||
|
// length > sizeof -> Return partial then 0
|
||||||
|
|
||||||
|
// 1st load for RX and auto-reload for TX
|
||||||
|
// We need to send something:
|
||||||
|
// - Set tx_buf and tx_pending to non-null and set TX to ACK
|
||||||
|
// - This piece of code shall handle loading to buffer
|
||||||
|
// - TX part shall start next transaction if we need to
|
||||||
|
// TX detects if the operation should be continued by checking
|
||||||
|
// if the tx_buf is null
|
||||||
|
|
||||||
|
// We are always handling either a TX or a RX transaction
|
||||||
|
// This is only for the control endpoint
|
||||||
|
if ( ep == 0 )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.USBD_SetupReqLen == 0 )
|
||||||
|
{
|
||||||
|
USBDCTX.pCtrlPayloadPtr = NULL;
|
||||||
|
// Enable recieving data
|
||||||
|
SetEPR_Status( 0, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_ACK );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// USBD_SEND_ACK is special variable to say 0 byte tx
|
||||||
|
if ( USBDCTX.USBD_SetupReqLen == USBD_SEND_ACK )
|
||||||
|
{
|
||||||
|
USBDCTX.USBD_SetupReqLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t tx_len = min( USBDCTX.USBD_SetupReqLen, USBD_PACKET_SIZE );
|
||||||
|
// Overreads but eh
|
||||||
|
for ( int i = 0; i < tx_len; i += 2 )
|
||||||
|
{
|
||||||
|
USBDCTX.usbd_ep_data_ptr[0][i / 2] = *( (const uint16_t *)( USBDCTX.pCtrlPayloadPtr + i ) );
|
||||||
|
}
|
||||||
|
USBD_BDT->EP[0].COUNTn_TX = tx_len;
|
||||||
|
USBDCTX.pCtrlPayloadPtr += tx_len;
|
||||||
|
USBDCTX.USBD_SetupReqLen -= tx_len;
|
||||||
|
SetEPR_Status( 0, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_ACK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IN request
|
||||||
|
if ( epr & USBD_CTR_TX )
|
||||||
|
{
|
||||||
|
if ( ep == 0 )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.USBD_SetupReqCode == USB_SET_ADDRESS )
|
||||||
|
{
|
||||||
|
USBD->DADDR = 0x80 | USBDCTX.USBD_DevAddr;
|
||||||
|
USBDCTX.USBD_DevAddr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Send data for non-zero endpoint
|
||||||
|
#if FUSB_USER_HANDLERS
|
||||||
|
len = HandleInRequest( &USBDCTX, ep, USBDCTX.endpoints[ep].in, 0 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ( len )
|
||||||
|
{
|
||||||
|
if ( len < 0 ) len = 0;
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_ACK );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_NAK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sent, no longer busy
|
||||||
|
USBDCTX.endpoints[ep].busy = 0;
|
||||||
|
|
||||||
|
// Clear TX (Toggle)
|
||||||
|
USBD->EPR[ep] = ( USBD->EPR[ep] & ( USBD_EA | USBD_EPKIND | USBD_EPTYPE ) ) | USBD_CTR_RX;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBD->ISTR = ~USBD_CTR;
|
||||||
|
return;
|
||||||
|
|
||||||
|
stall:
|
||||||
|
SetEPR_Status( 0, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_STALL );
|
||||||
|
SetEPR_Status( 0, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_STALL );
|
||||||
|
USBD->EPR[ep] = ( epr & ( USBD_EPR_EA | USBD_EPR_EP_TYPE_MASK | USBD_EPR_EP_KIND ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( istr & USBD_RESET )
|
||||||
|
{
|
||||||
|
USBD->ISTR = ~USBD_RESET;
|
||||||
|
USBD->BTABLE = 0;
|
||||||
|
|
||||||
|
for ( uint8_t ep = 0; ep < FUSB_MAX_EP_CNT; ++ep )
|
||||||
|
{
|
||||||
|
USBD->EPR[ep] = ep;
|
||||||
|
|
||||||
|
// TODO: Add method to set EP type
|
||||||
|
// Currently the user must override the function
|
||||||
|
// It seems that using TYPE_BULK is fine for all types though
|
||||||
|
SetEPR_Status( ep, USBD_EPR_EP_TYPE_MASK, USBD_EPR_EP_TYPE_BULK );
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_ACK );
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_NAK );
|
||||||
|
|
||||||
|
// Disable unused modes
|
||||||
|
if ( !( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_RX ) )
|
||||||
|
{
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_DIS );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !( USBDCTX.endpoints[ep].mode & USBD_EP_MODE_TX ) )
|
||||||
|
{
|
||||||
|
SetEPR_Status( ep, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_DIS );
|
||||||
|
}
|
||||||
|
USBDCTX.endpoints[ep].busy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override EP0 to control - mandatory
|
||||||
|
SetEPR_Status( 0, USBD_EPR_EP_TYPE_MASK, USBD_EPR_EP_TYPE_CTRL );
|
||||||
|
|
||||||
|
// Reset context
|
||||||
|
USBDCTX.USBD_DevConfig = 0;
|
||||||
|
USBDCTX.USBD_DevAddr = 0;
|
||||||
|
USBDCTX.USBD_DevSleepStatus = 0;
|
||||||
|
USBDCTX.USBD_DevEnumStatus = 0;
|
||||||
|
|
||||||
|
// Enable USB function (we default to address 0)
|
||||||
|
USBD->DADDR = USBD_EF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If size is a concern, merge this with the ISTR set bellow
|
||||||
|
if ( istr & ( USBD_ERR | USBD_PMAOVR ) )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf( "ERROR! USB error\n" );
|
||||||
|
#endif
|
||||||
|
USBD->ISTR = ~( USBD_ERR | USBD_PMAOVR );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't need the rest of the events, so we just default to resetting them
|
||||||
|
USBD->ISTR = ~( USBD_ESOF | USBD_SOF | USBD_WKUP | USBD_SUSP );
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t EP_buffer[USBD_PACKET_SIZE];
|
||||||
|
|
||||||
|
uint8_t *USBD_GetEPBufferIfAvailable( int endp )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.endpoints[endp].busy ) return 0;
|
||||||
|
return EP_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int USBD_SendEndpoint( int endp, int len )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.endpoints[endp].busy ) return -1;
|
||||||
|
if ( USBDCTX.USBD_SetupReqLen > 0 ) return -2;
|
||||||
|
|
||||||
|
for ( int i = 0; i < len; i += 2 )
|
||||||
|
{
|
||||||
|
USBDCTX.usbd_ep_data_ptr[endp][i / 2] = *( (const uint16_t *)( EP_buffer + i ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
USBD_BDT->EP[endp].COUNTn_TX = len;
|
||||||
|
USBDCTX.endpoints[endp].busy = 1;
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_ACK );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int USBD_SendEndpointNEW( int endp, uint8_t *data, int len, int copy )
|
||||||
|
{
|
||||||
|
if ( USBDCTX.endpoints[endp].busy ) return -1;
|
||||||
|
// This prevents sending while ep0 is receiving
|
||||||
|
if ( USBDCTX.USBD_SetupReqLen > 0 ) return USBDCTX.USBD_SetupReqLen;
|
||||||
|
|
||||||
|
// For FS compatability
|
||||||
|
USBDCTX.endpoints[endp].in = data;
|
||||||
|
|
||||||
|
for ( int i = 0; i + 1 < len; i += 2 )
|
||||||
|
{
|
||||||
|
USBDCTX.usbd_ep_data_ptr[endp][i / 2] = data[i] | ( (uint16_t)data[i + 1] << 8 );
|
||||||
|
}
|
||||||
|
if ( len % 2 != 0 )
|
||||||
|
{
|
||||||
|
USBDCTX.usbd_ep_data_ptr[endp][len / 2] = data[len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
USBD_BDT->EP[endp].COUNTn_TX = len;
|
||||||
|
USBDCTX.endpoints[endp].busy = 1;
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_ACK );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int USBD_SendACK( int endp, int tx )
|
||||||
|
{
|
||||||
|
if ( tx )
|
||||||
|
{
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_ACK );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_ACK );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int USBD_SendNAK( int endp, int tx )
|
||||||
|
{
|
||||||
|
if ( tx )
|
||||||
|
{
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_TX_MASK, USBD_EPR_STAT_TX_NAK );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetEPR_Status( endp, USBD_EPR_STAT_RX_MASK, USBD_EPR_STAT_RX_NAK );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF
|
||||||
|
uint8_t usb_inputbuffer[USBD_PACKET_SIZE];
|
||||||
|
int usb_inbuf_idx;
|
||||||
|
|
||||||
|
WEAK int HandleInRequest( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WEAK void HandleDataOut( struct _USBState *ctx, int endp, uint8_t *data, int len )
|
||||||
|
{
|
||||||
|
if ( endp == 0 )
|
||||||
|
{
|
||||||
|
ctx->USBD_SetupReqLen = 0; // To ACK
|
||||||
|
}
|
||||||
|
else if ( endp == 2 )
|
||||||
|
{
|
||||||
|
// discard oldest if polling is too slow
|
||||||
|
int headroom = ( sizeof( usb_inputbuffer ) - usb_inbuf_idx ) - len;
|
||||||
|
if ( headroom < 0 )
|
||||||
|
{
|
||||||
|
// not enough space left, free up some
|
||||||
|
int offset = -headroom;
|
||||||
|
for ( int i = offset; i < sizeof( usb_inputbuffer ); i++ )
|
||||||
|
{
|
||||||
|
usb_inputbuffer[i - offset] = usb_inputbuffer[i];
|
||||||
|
}
|
||||||
|
usb_inbuf_idx -= offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < len; i++ )
|
||||||
|
{
|
||||||
|
usb_inputbuffer[usb_inbuf_idx++] = data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void poll_input()
|
||||||
|
{
|
||||||
|
if ( usb_inbuf_idx )
|
||||||
|
{
|
||||||
|
HandleUSBInput( usb_inbuf_idx, usb_inputbuffer );
|
||||||
|
usb_inbuf_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WEAK int HandleSetupCustom( struct _USBState *ctx, int setup_code )
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
if ( ctx->USBD_SetupReqType & USB_REQ_TYP_CLASS )
|
||||||
|
{
|
||||||
|
switch ( setup_code )
|
||||||
|
{
|
||||||
|
case CDC_SET_LINE_CODING:
|
||||||
|
case CDC_SET_LINE_CTLSTE:
|
||||||
|
case CDC_SEND_BREAK: ret = ( ctx->USBD_SetupReqLen ) ? ctx->USBD_SetupReqLen : -1; break;
|
||||||
|
case CDC_GET_LINE_CODING: ret = ctx->USBD_SetupReqLen; break;
|
||||||
|
default: ret = 0; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = 0; // Go to STALL
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined( FUNCONF_USE_USBPRINTF ) && FUNCONF_USE_USBPRINTF
|
||||||
|
int USBFS_SendEndpointNEW( int endp, uint8_t *data, int len, int copy )
|
||||||
|
{
|
||||||
|
return USBD_SendEndpointNEW( endp, data, len, copy );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 201112L || defined( __GNUC__ ) || defined( __clang__ )
|
||||||
|
|
||||||
|
// Very hacky way to ensure that we don't get a BDT overflow
|
||||||
|
// I miss C++...
|
||||||
|
// This should more logically be in usbd.h, but we get multiple objects
|
||||||
|
// if we do that
|
||||||
|
//
|
||||||
|
// No checking on compilers w/o static assert :(
|
||||||
|
static const char _number_of_endpoints[] = {
|
||||||
|
#if FUSB_EP1_MODE
|
||||||
|
FUSB_EP1_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP2_MODE
|
||||||
|
FUSB_EP2_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP3_MODE
|
||||||
|
FUSB_EP3_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP4_MODE
|
||||||
|
FUSB_EP4_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP5_MODE
|
||||||
|
FUSB_EP5_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP6_MODE
|
||||||
|
FUSB_EP6_MODE,
|
||||||
|
#endif
|
||||||
|
#if FUSB_EP7_MODE
|
||||||
|
FUSB_EP7_MODE,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if __STDC_VERSION__ >= 202311L
|
||||||
|
static_assert( ( sizeof( _number_of_endpoints ) * USBD_PACKET_SIZE + USBD_PMA_BASE ) <= 512,
|
||||||
|
"USBD BDT overflow! Please use less endpoints, or make usbd packet size smaller" );
|
||||||
|
#elif defined( __GNUC__ ) || defined( __clang__ ) || __STDC_VERSION__ >= 201112L
|
||||||
|
_Static_assert( ( sizeof( _number_of_endpoints ) * USBD_PACKET_SIZE + USBD_PMA_BASE ) <= 512,
|
||||||
|
"USBD BDT overflow! Please use less endpoints, or make usbd packet size smaller" );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
187
inc/extralibs/usbd.h
Normal file
187
inc/extralibs/usbd.h
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
#ifndef USBD_H
|
||||||
|
#define USBD_H
|
||||||
|
|
||||||
|
#include "ch32fun.h"
|
||||||
|
#include "usb_config.h"
|
||||||
|
#include "usb_defines.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if defined(FUSB_FROM_RAM) && (FUSB_FROM_RAM)
|
||||||
|
#define __USBD_FUN_ATTRIBUTE __attribute__((section( ".srodata" ), used))
|
||||||
|
#else
|
||||||
|
#define __USBD_FUN_ATTRIBUTE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 0x400 of shared memory
|
||||||
|
// Up to 8 endpoints (0x10 each)
|
||||||
|
|
||||||
|
// Buffer Description Table
|
||||||
|
typedef struct __attribute__((__packed__))
|
||||||
|
{
|
||||||
|
USBD_BTABLE_TypeDef EP[8];
|
||||||
|
} USBD_BDT_TypeDef;
|
||||||
|
#define USBD_BDT ( (USBD_BDT_TypeDef *)CAN_USBD_SHARED_BASE )
|
||||||
|
|
||||||
|
// Packet buffer (0x400 - 0x80 = 0x380) left
|
||||||
|
#define USBD_PMA_BASE 0x80 // Offset from USBD_BDT_BASE
|
||||||
|
#define USBD_PACKET_SIZE 64
|
||||||
|
|
||||||
|
#define USBD_EPR_CTR_RX 0x8000
|
||||||
|
#define USBD_EPR_DTOG_RX 0x4000
|
||||||
|
#define USBD_EPR_STAT_RX_MASK 0x3000
|
||||||
|
#define USBD_EPR_STAT_RX_DIS 0x0000
|
||||||
|
#define USBD_EPR_STAT_RX_STALL 0x1000
|
||||||
|
#define USBD_EPR_STAT_RX_NAK 0x2000
|
||||||
|
#define USBD_EPR_STAT_RX_ACK 0x3000
|
||||||
|
#define USBD_EPR_SETUP 0x0800
|
||||||
|
#define USBD_EPR_EP_TYPE_MASK 0x0600
|
||||||
|
#define USBD_EPR_EP_TYPE_BULK 0x0000
|
||||||
|
#define USBD_EPR_EP_TYPE_CTRL 0x0200
|
||||||
|
#define USBD_EPR_EP_TYPE_ISO 0x0400
|
||||||
|
#define USBD_EPR_EP_TYPE_INT 0x0600
|
||||||
|
#define USBD_EPR_EP_KIND 0x0100
|
||||||
|
#define USBD_EPR_CTR_TX 0x0080
|
||||||
|
#define USBD_EPR_DTOG_TX 0x0040
|
||||||
|
#define USBD_EPR_STAT_TX_MASK 0x0030
|
||||||
|
#define USBD_EPR_STAT_TX_DIS 0x0000
|
||||||
|
#define USBD_EPR_STAT_TX_STALL 0x0010
|
||||||
|
#define USBD_EPR_STAT_TX_NAK 0x0020
|
||||||
|
#define USBD_EPR_STAT_TX_ACK 0x0030
|
||||||
|
#define USBD_EPR_EA 0x000F
|
||||||
|
|
||||||
|
#define USB_GET_STATUS 0x00
|
||||||
|
#define USB_SET_ADDRESS 0x05
|
||||||
|
#define USB_GET_DESCRIPTOR 0x06
|
||||||
|
#define USB_GET_CONFIG 0x08
|
||||||
|
#define USB_SET_CONFIG 0x09
|
||||||
|
#define USB_GET_INTERFACE 0x0A
|
||||||
|
|
||||||
|
#define USB_CLEAR_FEATURE 0x01
|
||||||
|
#define USB_SET_FEATURE 0x03
|
||||||
|
#define USB_SET_DESCRIPTOR 0x07
|
||||||
|
#define USB_SET_INTERFACE 0x0B
|
||||||
|
|
||||||
|
#define USBD_DEVICE_DESCRIPTOR 0x01
|
||||||
|
#define USBD_CONFIG_DESCRIPTOR 0x02
|
||||||
|
#define USBD_HID_DESCRIPTOR 0x22
|
||||||
|
#define USBD_STRING_DESCRIPTOR 0x03
|
||||||
|
|
||||||
|
#define USBD_REQ_TYP_MASK 0b01100000
|
||||||
|
#define USBD_REQ_TYP_STANDARD 0b00000000
|
||||||
|
#define USBD_REQ_TYP_CLASS 0b00100000
|
||||||
|
#define USBD_REQ_TYP_VENDOR 0b01000000
|
||||||
|
|
||||||
|
#define USBD_EP_MODE_TX 4
|
||||||
|
#define USBD_EP_MODE_RX 8
|
||||||
|
#define USBD_EP_MODE_BDIR 12
|
||||||
|
|
||||||
|
// Magic value for ack
|
||||||
|
#define USBD_SEND_ACK (0xFFFF)
|
||||||
|
|
||||||
|
#ifndef USBD_SILENCE_EP_MODE
|
||||||
|
#ifdef USBFS_EP_MODE_RX
|
||||||
|
#warning USBFS_EP_MODE_RX "USBD should use USBD_EP_MODE_RX instead of USBFS_EP_MODE_RX unless also using USBFS (silence by defining USBD_SILENCE_EP_MODE)"
|
||||||
|
#endif
|
||||||
|
#ifdef USBFS_EP_MODE_TX
|
||||||
|
#warning USBFS_EP_MODE_TX "USBD should use USBD_EP_MODE_TX instead of USBFS_EP_MODE_TX unless also using USBFS (silence by defining USBD_SILENCE_EP_MODE)"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _USBState;
|
||||||
|
|
||||||
|
int USBDSetup( void );
|
||||||
|
void USBDReset( void );
|
||||||
|
uint8_t *USBD_GetEPBufferIfAvailable( int endp ); // Only 1 buffer might be active at a time
|
||||||
|
int USBD_SendEndpoint( int endp, int len );
|
||||||
|
int USBD_SendEndpointNEW( int endp, uint8_t *data, int len, int copy ); // Copy is ignored
|
||||||
|
int USBD_SendACK( int endp, int tx );
|
||||||
|
int USBD_SendNAK( int endp, int tx );
|
||||||
|
|
||||||
|
#if FUSB_HID_USER_REPORTS
|
||||||
|
int HandleHidUserGetReportSetup( struct _USBState *ctx, tusb_control_request_t *req );
|
||||||
|
int HandleHidUserSetReportSetup( struct _USBState *ctx, tusb_control_request_t *req );
|
||||||
|
void HandleHidUserReportDataOut( struct _USBState *ctx, uint8_t *data, int len );
|
||||||
|
int HandleHidUserReportDataIn( struct _USBState *ctx, uint8_t *data, int len );
|
||||||
|
void HandleHidUserReportOutComplete( struct _USBState *ctx );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUSB_USER_HANDLERS
|
||||||
|
int HandleInRequest( struct _USBState *ctx, int endp, uint8_t *data, int len );
|
||||||
|
void HandleDataOut( struct _USBState *ctx, int endp, uint8_t *data, int len );
|
||||||
|
int HandleSetupCustom( struct _USBState *ctx, int setup_code );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FUNCONF_USE_USBPRINTF
|
||||||
|
void HandleUSBInput( int numbytes, uint8_t *data );
|
||||||
|
extern uint8_t usb_inputbuffer[USBD_PACKET_SIZE];
|
||||||
|
extern int usb_inbuf_idx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FUSB_MAX_EP_CNT
|
||||||
|
#define FUSB_MAX_EP_CNT 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined( FUSB_BUFFERS_NUMBER ) || FUSB_BUFFERS_NUMBER == 0
|
||||||
|
#define FUSB_BUFFERS_NUMBER 1
|
||||||
|
#undef FUSB_EP1_MODE
|
||||||
|
#define FUSB_EP1_MODE 0
|
||||||
|
#undef FUSB_EP2_MODE
|
||||||
|
#define FUSB_EP2_MODE 0
|
||||||
|
#undef FUSB_EP3_MODE
|
||||||
|
#define FUSB_EP3_MODE 0
|
||||||
|
#undef FUSB_EP4_MODE
|
||||||
|
#define FUSB_EP4_MODE 0
|
||||||
|
#undef FUSB_EP5_MODE
|
||||||
|
#define FUSB_EP5_MODE 0
|
||||||
|
#undef FUSB_EP6_MODE
|
||||||
|
#define FUSB_EP6_MODE 0
|
||||||
|
#undef FUSB_EP7_MODE
|
||||||
|
#define FUSB_EP7_MODE 0
|
||||||
|
#warning "You may have forgotten to properly define used EPs in usb_config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct _USBState
|
||||||
|
{
|
||||||
|
// Setup Request
|
||||||
|
uint8_t USBD_SetupReqCode;
|
||||||
|
uint8_t USBD_SetupReqType;
|
||||||
|
uint16_t USBD_SetupReqLen; // Used for tracking place along send.
|
||||||
|
uint32_t USBD_IndexValue;
|
||||||
|
|
||||||
|
// USB Device Status
|
||||||
|
uint8_t USBD_DevConfig;
|
||||||
|
uint8_t USBD_DevAddr;
|
||||||
|
uint8_t USBD_DevSleepStatus;
|
||||||
|
uint8_t USBD_DevEnumStatus;
|
||||||
|
|
||||||
|
uint8_t *pCtrlPayloadPtr;
|
||||||
|
|
||||||
|
uint32_t *usbd_ep_data_ptr[FUSB_MAX_EP_CNT];
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
uint8_t *in;
|
||||||
|
uint8_t *tx;
|
||||||
|
};
|
||||||
|
uint8_t mode;
|
||||||
|
uint8_t busy;
|
||||||
|
} endpoints[FUSB_MAX_EP_CNT];
|
||||||
|
|
||||||
|
#if FUSB_HID_INTERFACES > 0
|
||||||
|
uint8_t USBD_HidIdle[FUSB_HID_INTERFACES];
|
||||||
|
uint8_t USBD_HidProtocol[FUSB_HID_INTERFACES];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We don't really need buffers for other endpoints
|
||||||
|
// We waste 64 bytes to prevent overflows (why are overflows happening??)
|
||||||
|
// This was probably fine in other demos
|
||||||
|
// But here we only have 1 buffer
|
||||||
|
uint8_t ep0buf[2][USBD_PACKET_SIZE];
|
||||||
|
#define CTRL0BUFF ( USBDCTX.ep0buf[0] )
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct _USBState USBDCTX;
|
||||||
|
|
||||||
|
#endif // USBD_H
|
||||||
Loading…
Add table
Reference in a new issue