Merge pull request #15 from RT-Thread/master

pr
This commit is contained in:
Meco Man 2021-02-05 20:44:25 +08:00 committed by GitHub
commit 852d7d7552
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
127 changed files with 12835 additions and 924 deletions

View File

@ -38,7 +38,6 @@ jobs:
- {RTT_BSP: "gd32e230k-start", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "gd32303e-eval", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "gd32450z-eval", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "gkipc", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "imx6sx/cortex-a9", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "imxrt/imxrt1052-atk-commander", RTT_TOOL_CHAIN: "sourcery-arm"}
- {RTT_BSP: "imxrt/imxrt1052-fire-pro", RTT_TOOL_CHAIN: "sourcery-arm"}

View File

@ -17,7 +17,7 @@ if CROSS_TOOL == 'gcc':
PLATFORM = 'gcc'
EXEC_PATH = r'E:\work\env\tools\gnu_gcc\arm_gcc\mingw\bin'
else:
print 'Please make sure your toolchains is GNU GCC!'
print('Please make sure your toolchains is GNU GCC!')
exit(0)
if os.getenv('RTT_EXEC_PATH'):

View File

@ -107,26 +107,7 @@ CONFIG_FINSH_ARG_MAX=10
#
# Device virtual file system
#
CONFIG_RT_USING_DFS=y
CONFIG_DFS_USING_WORKDIR=y
CONFIG_DFS_FILESYSTEMS_MAX=2
CONFIG_DFS_FILESYSTEM_TYPES_MAX=2
CONFIG_DFS_FD_MAX=16
# CONFIG_RT_USING_DFS_MNTTABLE is not set
# CONFIG_RT_USING_DFS_ELMFAT is not set
# CONFIG_RT_DFS_ELM_USE_LFN_0 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_1 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
# CONFIG_RT_DFS_ELM_USE_LFN_3 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_0 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set
# CONFIG_RT_USING_DFS_DEVFS is not set
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_UFFS is not set
# CONFIG_RT_USING_DFS_JFFS2 is not set
# CONFIG_RT_USING_DFS is not set
#
# Device Drivers
@ -172,7 +153,6 @@ CONFIG_RT_USING_PIN=y
#
CONFIG_RT_USING_LIBC=y
# CONFIG_RT_USING_PTHREADS is not set
# CONFIG_RT_USING_POSIX is not set
# CONFIG_RT_USING_MODULE is not set
#
@ -395,6 +375,7 @@ CONFIG_RT_USING_LIBC=y
# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set
# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
# CONFIG_PKG_USING_QFPLIB_M3 is not set
# CONFIG_PKG_USING_LPM is not set
#
# peripheral libraries and drivers
@ -525,8 +506,11 @@ CONFIG_BSP_USING_USB_TO_USART=y
CONFIG_BSP_USING_UART0=y
# CONFIG_BSP_USING_SDIO is not set
# CONFIG_BSP_USING_I2C1 is not set
# CONFIG_BSP_USING_PWM is not set
# CONFIG_BSP_USING_WDT is not set
# CONFIG_BSP_USING_TIM is not set
# CONFIG_BSP_USING_ONCHIP_RTC is not set
# CONFIG_BSP_USING_ADC is not set
#
# Board extended module Drivers

View File

@ -30,26 +30,26 @@ ab32vg1-prougen 是 中科蓝讯(Bluetrum) 推出的一款基于 RISC-V 内核
本 BSP 目前对外设的支持情况如下:
| **板载外设** | **支持情况** | **备注** |
| :----------- | :----------: | :---------- |
| USB 转串口 | 支持 | |
| SD卡 | 支持 | |
| IRDA | 即将支持 | |
| 音频接口 | 支持 | |
| **片上外设** | **支持情况** | **备注** |
| GPIO | 支持 | PA PB PE PF |
| UART | 支持 | UART0/1/2 |
| SDIO | 支持 | |
| ADC | 即将支持 | |
| SPI | 即将支持 | 软件 SPI |
| I2C | 支持 | 软件 I2C |
| RTC | 即将支持 | |
| WDT | 支持 | |
| FLASH | 即将支持 | |
| TIMER | 支持 | |
| PWM | 即将支持 | |
| USB Device | 暂不支持 | |
| USB Host | 暂不支持 | |
| **板载外设** | **支持情况** | **备注** |
| :----------- | :----------: | :---------------------------------------- |
| USB 转串口 | 支持 | |
| SD卡 | 支持 | |
| IRDA | 即将支持 | |
| 音频接口 | 支持 | |
| **片上外设** | **支持情况** | **备注** |
| GPIO | 支持 | PA PB PE PF |
| UART | 支持 | UART0/1/2 |
| SDIO | 支持 | |
| ADC | 即将支持 | |
| SPI | 即将支持 | 软件 SPI |
| I2C | 支持 | 软件 I2C |
| RTC | 即将支持 | |
| WDT | 支持 | |
| FLASH | 即将支持 | |
| TIMER | 支持 | |
| PWM | 支持 | LPWM 的 G1 G2 G3 之间是互斥的,只能三选一 |
| USB Device | 暂不支持 | |
| USB Host | 暂不支持 | |
## 使用说明

View File

@ -65,6 +65,72 @@ menu "On-chip Peripheral Drivers"
default 15
endif
menuconfig BSP_USING_PWM
bool "Enable PWM"
default n
select RT_USING_PWM
if BSP_USING_PWM
menuconfig BSP_USING_T3_PWM
bool "Enable Timer3 PWM"
default n
if BSP_USING_T3_PWM
config BSP_USING_T3_PWM0
bool "Enable Timer3 PWM0 (PB0)(Confict with SD card)"
default n
endif
menuconfig BSP_USING_T4_PWM
bool "Enable Timer4 PWM"
default n
if BSP_USING_T4_PWM
config BSP_USING_T4_PWM1
bool "Enable Timer4 PWM1 (PA6)(Confit with uart0 rx)"
default n
endif
menuconfig BSP_USING_T5_PWM
bool "Enable Timer5 PWM"
default n
if BSP_USING_T5_PWM
config BSP_USING_T5_PWM0
bool "Enable Timer5 PWM2 (PE1)"
default n
endif
menuconfig BSP_USING_LPWM0
bool "Enable LPWM0"
default n
if BSP_USING_LPWM0
comment "G1, G2 and G3 are mutually exclusive"
config BSP_USING_LPWM0_G1
bool "Enable LPWM0 G1 (PE4)"
default n
endif
menuconfig BSP_USING_LPWM1
bool "Enable LPWM1"
default n
if BSP_USING_LPWM1
comment "G1, G2 and G3 are mutually exclusive"
config BSP_USING_LPWM1_G3
bool "Enable LPWM1 G3 (PA1)"
default n
endif
menuconfig BSP_USING_LPWM2
bool "Enable LPWM2"
default n
if BSP_USING_LPWM2
comment "G1, G2 and G3 are mutually exclusive"
config BSP_USING_LPWM2_G2
bool "Enable LPWM2 G2 (PE0)"
default n
config BSP_USING_LPWM2_G3
bool "Enable LPWM2 G3 (PA2)"
default n
endif
endif
config BSP_USING_WDT
bool "Enable Watchdog Timer"
select RT_USING_WDT
@ -96,6 +162,22 @@ menu "On-chip Peripheral Drivers"
default n
endif
config BSP_USING_ONCHIP_RTC
bool "Enable RTC"
select RT_USING_RTC
select RT_USING_LIBC
default n
menuconfig BSP_USING_ADC
bool "Enable ADC"
default n
select RT_USING_ADC
if BSP_USING_ADC
config BSP_USING_ADC0
bool "Enable ADC0"
default n
endif
endmenu
menu "Board extended module Drivers"

View File

@ -1,9 +1,10 @@
/*
* Copyright (c) 2020-2020, BLUETRUM Development Team
* Copyright (c) 2020-2021, BLUETRUM Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <rtthread.h>
#include "ab32vg1_hal.h"
void hal_uart_mspinit(struct uart_handle *huart)
@ -63,3 +64,60 @@ void hal_sd_mspinit(sd_handle_t hsd)
hal_gpio_init(GPIOB_BASE, &gpio_init);
}
#endif
void hal_pwm_mspinit(void)
{
struct gpio_init gpio_init = {0};
gpio_init.dir = GPIO_DIR_OUTPUT;
gpio_init.de = GPIO_DIGITAL;
#ifdef BSP_USING_T3_PWM0
gpio_init.pin = GPIO_PIN_0;
gpio_init.alternate = GPIO_AF_MAP_Gx(TMR3MAP_AF, GPIO_AF_G1);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON2;
hal_gpio_init(GPIOB_BASE, &gpio_init);
#endif
#ifdef BSP_USING_T4_PWM1
gpio_init.pin = GPIO_PIN_6;
gpio_init.alternate = GPIO_AF_MAP_Gx(TMR4MAP_AF, GPIO_AF_G1);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON2;
hal_gpio_init(GPIOA_BASE, &gpio_init);
#endif
#ifdef BSP_USING_T5_PWM0
gpio_init.pin = GPIO_PIN_1;
gpio_init.alternate = GPIO_AF_MAP_Gx(TMR5MAP_AF, GPIO_AF_G1);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON2;
hal_gpio_init(GPIOE_BASE, &gpio_init);
#endif
#ifdef BSP_USING_LPWM0_G1
gpio_init.pin = GPIO_PIN_4;
gpio_init.alternate = GPIO_AF_MAP_Gx(LPWM0MAP_AF, GPIO_AF_G1);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON1;
hal_gpio_init(GPIOE_BASE, &gpio_init);
#endif
#ifdef BSP_USING_LPWM1_G3
gpio_init.pin = GPIO_PIN_1;
gpio_init.alternate = GPIO_AF_MAP_Gx(LPWM1MAP_AF, GPIO_AF_G3);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON1;
hal_gpio_init(GPIOA_BASE, &gpio_init);
#endif
#ifdef BSP_USING_LPWM2_G2
gpio_init.pin = GPIO_PIN_0;
gpio_init.alternate = GPIO_AF_MAP_Gx(LPWM2MAP_AF, GPIO_AF_G2);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON1;
hal_gpio_init(GPIOE_BASE, &gpio_init);
#endif
#ifdef BSP_USING_LPWM2_G3
gpio_init.pin = GPIO_PIN_2;
gpio_init.alternate = GPIO_AF_MAP_Gx(LPWM2MAP_AF, GPIO_AF_G3);
gpio_init.af_con = GPIO_AFEN | GPIO_AFCON1;
hal_gpio_init(GPIOA_BASE, &gpio_init);
#endif
}

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:

View File

@ -1,6 +1,6 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2020, Bluetrum Development Team
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*

View File

@ -40,16 +40,6 @@ SECTIONS
KEEP(*(SORT(.rti_fn*)))
__rt_init_end = .;
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
. = ALIGN(4);
PROVIDE(__ctors_start__ = .);
KEEP (*(SORT(.init_array.*)))
@ -59,9 +49,6 @@ SECTIONS
. = ALIGN(4);
*components*drivers**.o (.text*)
*components.o (.text*)
*idle.o (.text*)
*object.o (.text*)
*scheduler.o (.text*)
} > ram1 AT > flash
.comm __comm_vma : {
@ -70,7 +57,9 @@ SECTIONS
EXCLUDE_FILE(*components*finsh**.o *components*libc**.o *dfs*filesystems**.o
*romfs.o *lib_a**.o *divdi3.o *moddi3.o *divdf3.o *muldf3.o *eqtf2.o *getf2.o
*letf2.o *multf3.o *subtf3.o *fixtfsi.o *floatsitf.o *extenddftf2.o
*trunctfdf2.o *_clzsi2.o *cp-demangle.o *unwind*.o) *(.text)
*trunctfdf2.o *_clzsi2.o *cp-demangle.o *unwind*.o
*fixdfsi.o *addsf3.o *divsf3.o *eqsf2.o *gesf2.o *float*.o
*lesf2.o *mulsf3.o *subsf3.o *fixsfsi.o *fixunssfsi.o) *(.text)
*finsh*shell.o (.text*)
*(.text.unlikely)
*(.text.startup)
@ -109,6 +98,17 @@ SECTIONS
} > heap
.flash : {
. = ALIGN(4);
__fsymtab_start = .;
KEEP(*(FSymTab))
__fsymtab_end = .;
. = ALIGN(4);
__vsymtab_start = .;
KEEP(*(VSymTab))
__vsymtab_end = .;
*(.text*)
*(.rodata*)
*(.srodata*)

View File

@ -72,11 +72,6 @@
/* Device virtual file system */
#define RT_USING_DFS
#define DFS_USING_WORKDIR
#define DFS_FILESYSTEMS_MAX 2
#define DFS_FILESYSTEM_TYPES_MAX 2
#define DFS_FD_MAX 16
/* Device Drivers */

View File

@ -25,6 +25,15 @@ if GetDepend('RT_USING_WDT'):
if GetDepend('RT_USING_HWTIMER'):
src += ['drv_hwtimer.c']
if GetDepend('RT_USING_PWM'):
src += ['drv_pwm.c']
if GetDepend('RT_USING_RTC'):
src += ['drv_rtc.c']
if GetDepend('RT_USING_ADC'):
src += ['drv_adc.c']
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = path)
objs = [group]

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-02-01 greedyhao first version
*/
#ifndef __ADC_CONFIG_H__
#define __ADC_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef BSP_USING_ADC0
#ifndef ADC0_CONFIG
#define ADC0_CONFIG \
{ \
.adc_dat_handle = (hal_sfr_t)&SADCDAT0, \
.name = "adc0", \
}
#endif /* ADC0_CONFIG */
#endif /* BSP_USING_ADC0 */
#ifdef __cplusplus
}
#endif
#endif

View File

@ -4,6 +4,110 @@
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021/01/18 greedyhao The first version
* Date Author Notes
* 2021-01-28 greedyhao first version
*/
#ifndef __PWM_CONFIG_H__
#define __PWM_CONFIG_H__
#include <rtthread.h>
#ifdef __cplusplus
extern "C" {
#endif
enum
{
PWMxCON,
PWMxPR,
PWMxxDUT,
PWMyyDUT,
PWMxCYCNUM,
PWMxSTEP,
};
#define PWM_BASE ((hal_sfr_t)&PWMCON)
#ifdef BSP_USING_T3_PWM
#ifndef T3_PWM_CONFIG
#define T3_PWM_CONFIG \
{ \
.pwm_handle = TIM3_BASE, \
.name = "t3pwm", \
.channel = 0 \
}
#endif /* T3_PWM_CONFIG */
#endif /* BSP_USING_T3_PWM */
#ifdef BSP_USING_T4_PWM
#ifndef T4_PWM_CONFIG
#define T4_PWM_CONFIG \
{ \
.pwm_handle = TIM4_BASE, \
.name = "t4pwm", \
.channel = 0 \
}
#endif /* T4_PWM_CONFIG */
#endif /* BSP_USING_T4_PWM */
#ifdef BSP_USING_T5_PWM
#ifndef T5_PWM_CONFIG
#define T5_PWM_CONFIG \
{ \
.pwm_handle = TIM5_BASE, \
.name = "t5pwm", \
.channel = 0 \
}
#endif /* T5_PWM_CONFIG */
#endif /* BSP_USING_T5_PWM */
#ifdef BSP_USING_LPWM0
#ifndef LPWM0_CONFIG
#define LPWM0_CONFIG \
{ \
.pwm_handle = PWM_BASE, \
.name = "lpwm0", \
.channel = 0 \
}
#endif /* LPWM0_CONFIG */
#endif /* BSP_USING_LPWM0 */
#ifdef BSP_USING_LPWM1
#ifndef LPWM1_CONFIG
#define LPWM1_CONFIG \
{ \
.pwm_handle = PWM_BASE, \
.name = "lpwm1", \
.channel = 0 \
}
#endif /* LPWM1_CONFIG */
#endif /* BSP_USING_LPWM1 */
#ifdef BSP_USING_LPWM2
#ifndef LPWM2_CONFIG
#define LPWM2_CONFIG \
{ \
.pwm_handle = PWM_BASE, \
.name = "lpwm2", \
.channel = 0 \
}
#endif /* LPWM2_CONFIG */
#endif /* BSP_USING_LPWM2 */
#ifdef BSP_USING_LPWM3
#ifndef LPWM3_CONFIG
#define LPWM3_CONFIG \
{ \
.pwm_handle = PWM_BASE, \
.name = "lpwm3", \
.channel = 0 \
}
#endif /* LPWM3_CONFIG */
#endif /* BSP_USING_LPWM3 */
#ifdef __cplusplus
}
#endif
#endif /* __PWM_CONFIG_H__ */

View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-02-01 greedyhao first version
*/
#include "drv_gpio.h"
#ifdef BSP_USING_ADC0
#include "adc_config.h"
// #define DRV_DEBUG
#define LOG_TAG "drv.adc"
#include <drv_log.h>
struct ab32_adc
{
struct rt_adc_device ab32_adc_device;
hal_sfr_t adc_dat_handle;
char *name;
};
enum
{
#ifdef BSP_USING_ADC0
ADC0_INDEX,
#endif
ADC_INDEX_END
};
static struct ab32_adc ab32_adc_obj[] =
{
#ifdef BSP_USING_ADC0
ADC0_CONFIG,
#endif
};
static rt_err_t ab32_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
{
RT_ASSERT(device != RT_NULL);
hal_adc_enable(enabled);
return RT_EOK;
}
static rt_uint32_t ab32_adc_get_channel(rt_uint32_t channel)
{
rt_uint32_t ab32_channel = 0;
switch (channel)
{
case 0:
ab32_channel = ADC_CHANNEL_0;
break;
case 1:
ab32_channel = ADC_CHANNEL_1;
break;
case 2:
ab32_channel = ADC_CHANNEL_2;
break;
case 3:
ab32_channel = ADC_CHANNEL_3;
break;
case 4:
ab32_channel = ADC_CHANNEL_4;
break;
case 5:
ab32_channel = ADC_CHANNEL_5;
break;
case 6:
ab32_channel = ADC_CHANNEL_6;
break;
case 7:
ab32_channel = ADC_CHANNEL_7;
break;
case 8:
ab32_channel = ADC_CHANNEL_8;
break;
case 9:
ab32_channel = ADC_CHANNEL_9;
break;
case 10:
ab32_channel = ADC_CHANNEL_10;
break;
case 11:
ab32_channel = ADC_CHANNEL_11;
break;
case 12:
ab32_channel = ADC_CHANNEL_12;
break;
case 13:
ab32_channel = ADC_CHANNEL_13;
break;
case 14:
ab32_channel = ADC_CHANNEL_14;
break;
case 15:
ab32_channel = ADC_CHANNEL_15;
break;
}
return ab32_channel;
}
static rt_err_t ab32_get_adc_value(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
{
hal_sfr_t ab32_adc_handler;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(value != RT_NULL);
ab32_adc_handler = device->parent.user_data;
hal_adc_start(ab32_adc_get_channel(channel));
hal_adc_poll_for_conversion(1000);
*value = ab32_adc_handler[channel];
return RT_EOK;
}
static const struct rt_adc_ops _adc_ops =
{
.enabled = ab32_adc_enabled,
.convert = ab32_get_adc_value,
};
static int ab32_adc_init(void)
{
int result = RT_EOK;
int i = 0;
if (ADC_INDEX_END == 0) {
return result;
}
CLKCON0 |= BIT(28); // enable adc clock
for (i = 0; i < sizeof(ab32_adc_obj) / sizeof(ab32_adc_obj[0]); i++) {
if (rt_hw_adc_register(&ab32_adc_obj[i].ab32_adc_device, ab32_adc_obj[i].name, &_adc_ops, (const void *)ab32_adc_obj[i].adc_dat_handle) == RT_EOK)
{
LOG_D("%s init success", ab32_adc_obj[i].name);
}
else
{
LOG_E("%s register failed", ab32_adc_obj[i].name);
result = -RT_ERROR;
}
}
return result;
}
INIT_BOARD_EXPORT(ab32_adc_init);
#endif

View File

@ -0,0 +1,334 @@
/*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-28 greedyhao first version
*/
#include <board.h>
#ifdef RT_USING_PWM
#include "pwm_config.h"
//#define DRV_DEBUG
#define LOG_TAG "drv.pwm"
#include <drv_log.h>
#define MAX_PERIOD 65535
#define MIN_PERIOD 3
#define MIN_PULSE 2
void hal_pwm_mspinit(void);
enum
{
#ifdef BSP_USING_T3_PWM
T3_PWM_INDEX,
#endif
#ifdef BSP_USING_T4_PWM
T4_PWM_INDEX,
#endif
#ifdef BSP_USING_T5_PWM
T5_PWM_INDEX,
#endif
#ifdef BSP_USING_LPWM0
LPWM0_INDEX,
#endif
#ifdef BSP_USING_LPWM1
LPWM1_INDEX,
#endif
#ifdef BSP_USING_LPWM2
LPWM2_INDEX,
#endif
#ifdef BSP_USING_LPWM3
LPWM3_INDEX,
#endif
};
struct ab32_pwm
{
struct rt_device_pwm pwm_device;
hal_sfr_t pwm_handle;
char *name;
rt_uint8_t channel;
rt_uint32_t period;
rt_uint32_t pulse;
};
static struct ab32_pwm ab32_pwm_obj[] =
{
#ifdef BSP_USING_T3_PWM
T3_PWM_CONFIG,
#endif
#ifdef BSP_USING_T4_PWM
T4_PWM_CONFIG,
#endif
#ifdef BSP_USING_T5_PWM
T5_PWM_CONFIG,
#endif
#ifdef BSP_USING_LPWM0
LPWM0_CONFIG,
#endif
#ifdef BSP_USING_LPWM1
LPWM1_CONFIG,
#endif
#ifdef BSP_USING_LPWM2
LPWM2_CONFIG,
#endif
#ifdef BSP_USING_LPWM3
LPWM3_CONFIG,
#endif
};
static rt_err_t drv_pwm_enable(hal_sfr_t pwm, char *name, struct rt_pwm_configuration *configuration, rt_bool_t enable)
{
rt_uint8_t channel = configuration->channel;
rt_uint8_t pwm_num = 0;
if (!configuration->complementary) {
if (name[0] == 'l') {
pwm[PWMxCON] &= ~BIT(5);
}
} else {
if (name[0] == 'l') {
pwm[PWMxCON] |= BIT(5);
} else {
LOG_W("Timer no support complementary PWM output!");
}
}
if (!enable) {
if (name[0] == 'l') {
pwm_num = name[4] - '0';
pwm[PWMxCON] &= ~(1 << (pwm_num));
} else {
if (channel & 0x1) { /* pwm0 */
pwm[TMRxCON] &= ~(1 << (9 + 0));
}
if (channel & 0x2) { /* pwm1 */
pwm[TMRxCON] &= ~(1 << (9 + 1));
}
if (channel & 0x4) { /* pwm2 */
pwm[TMRxCON] &= ~(1 << (9 + 2));
}
}
} else {
if (name[0] == 'l') {
pwm_num = name[4] - '0';
pwm[PWMxCON] |= 1 << (pwm_num);
} else {
if (channel & 0x1) { /* pwm0 */
pwm[TMRxCON] |= (1 << (9 + 0));
}
if (channel & 0x2) { /* pwm1 */
pwm[TMRxCON] |= (1 << (9 + 1));
}
if (channel & 0x4) { /* pwm2 */
pwm[TMRxCON] |= (1 << (9 + 2));
}
}
}
return RT_EOK;
}
static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
{
struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
struct ab32_pwm *pwm_obj = (struct ab32_pwm *)device->parent.user_data;
hal_sfr_t pwm = pwm_obj->pwm_handle;
char *name = pwm_obj->name;
rt_uint8_t channel = configuration->channel;
rt_uint32_t period, pulse;
rt_uint64_t tim_clock, psc;
if (name[0] == 'l') {
tim_clock = 6500; /* lpwm clock is 6.5MHz */
} else {
tim_clock = get_sysclk_nhz() / 1000ul;
}
switch (cmd)
{
case PWMN_CMD_ENABLE:
configuration->complementary = RT_TRUE;
case PWM_CMD_ENABLE:
return drv_pwm_enable(pwm, name, configuration, RT_TRUE);
case PWMN_CMD_DISABLE:
configuration->complementary = RT_FALSE;
case PWM_CMD_DISABLE:
return drv_pwm_enable(pwm, name, configuration, RT_FALSE);
case PWM_CMD_SET:
pwm_obj->pulse = configuration->pulse;
pwm_obj->period = configuration->period;
period = pwm_obj->period * tim_clock / 1000000ul;
psc = period / MAX_PERIOD + 1;
period = period / psc;
if (period < MIN_PERIOD)
{
period = MIN_PERIOD;
}
pulse = pwm_obj->pulse * tim_clock / psc / 1000000ul;
if (pulse < MIN_PULSE)
{
pulse = MIN_PULSE;
}
else if (pulse > period)
{
pulse = period;
}
if (name[0] == 'l') {
pwm[PWMxPR] = period - 1;
switch (name[4] - '0')
{
case 0: /* lpwm0 */
pwm[PWMxxDUT] = pulse - 1;
break;
case 1: /* lpwm1 */
pwm[PWMxxDUT] = (pulse - 1) << 16;
break;
case 2: /* lpwm2 */
pwm[PWMyyDUT] = pulse - 1;
break;
case 3: /* lpwm3 */
pwm[PWMyyDUT] = (pulse - 1) << 16;
break;
default:
break;
}
} else {
pwm[TMRxPR] = period - 1;
if (channel & 0x1) { /* pwm0 */
pwm[TMRxDUTY0] = pulse - 1;
}
if (channel & 0x2) { /* pwm1 */
pwm[TMRxDUTY1] = pulse - 1;
}
if (channel & 0x4) { /* pwm2 */
pwm[TMRxDUTY2] = pulse - 1;
}
}
return RT_EOK;
case PWM_CMD_GET:
configuration->pulse = pwm_obj->pulse;
configuration->period = pwm_obj->period;
return RT_EOK;
default:
return -RT_EINVAL;
}
}
static rt_err_t ab32_hw_pwm_init(struct ab32_pwm *device)
{
rt_err_t result = RT_EOK;
hal_sfr_t pwm = RT_NULL;
char *name = RT_NULL;
RT_ASSERT(device != RT_NULL);
pwm = (hal_sfr_t)device->pwm_handle;
name = device->name;
if (name[0] == 'l') {
pwm[PWMxCON] = 0;
} else {
pwm[TMRxCON] &= ~(7 << 9);
}
return result;
}
static void pwm_get_channel(void)
{
#ifdef BSP_USING_T3_PWM0
ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_T3_PWM1
ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 1;
#endif
#ifdef BSP_USING_T3_PWM2
ab32_pwm_obj[T3_PWM_INDEX].channel |= 1 << 2;
#endif
#ifdef BSP_USING_T4_PWM0
ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_T4_PWM1
ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 1;
#endif
#ifdef BSP_USING_T4_PWM2
ab32_pwm_obj[T4_PWM_INDEX].channel |= 1 << 2;
#endif
#ifdef BSP_USING_T5_PWM0
ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_T5_PWM1
ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 1;
#endif
#ifdef BSP_USING_T5_PWM2
ab32_pwm_obj[T5_PWM_INDEX].channel |= 1 << 2;
#endif
#ifdef BSP_USING_LPWM0
ab32_pwm_obj[LPWM0_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_LPWM1
ab32_pwm_obj[LPWM1_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_LPWM2
ab32_pwm_obj[LPWM2_INDEX].channel |= 1 << 0;
#endif
#ifdef BSP_USING_LPWM3
ab32_pwm_obj[LPWM3_INDEX].channel |= 1 << 0;
#endif
}
static struct rt_pwm_ops drv_ops =
{
drv_pwm_control
};
static int ab32_pwm_init(void)
{
int i = 0;
int result = RT_EOK;
pwm_get_channel();
hal_pwm_mspinit();
for (i = 0; i < sizeof(ab32_pwm_obj) / sizeof(ab32_pwm_obj[0]); i++)
{
/* pwm init */
if (ab32_hw_pwm_init(&ab32_pwm_obj[i]) != RT_EOK)
{
LOG_E("%s init failed", ab32_pwm_obj[i].name);
result = -RT_ERROR;
goto __exit;
}
else
{
LOG_D("%s init success", ab32_pwm_obj[i].name);
/* register pwm device */
if (rt_device_pwm_register(&ab32_pwm_obj[i].pwm_device, ab32_pwm_obj[i].name, &drv_ops, (void *)&ab32_pwm_obj[i]) == RT_EOK)
{
LOG_D("%s register success", ab32_pwm_obj[i].name);
}
else
{
LOG_E("%s register failed", ab32_pwm_obj[i].name);
result = -RT_ERROR;
}
}
}
__exit:
return result;
}
INIT_DEVICE_EXPORT(ab32_pwm_init);
#endif /* RT_USING_PWM */

View File

@ -0,0 +1,218 @@
/*
* Copyright (c) 2020-2021, Bluetrum Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-01-28 greedyhao first version
*/
#include "board.h"
#include <time.h>
#ifdef BSP_USING_ONCHIP_RTC
//#define DRV_DEBUG
#define LOG_TAG "drv.rtc"
#include <drv_log.h>
static struct rt_device rtc;
/************** HAL Start *******************/
#define IRTC_ENTER_CRITICAL() uint32_t cpu_ie = PICCON & BIT(0); PICCONCLR = BIT(0);
#define IRTC_EXIT_CRITICAL() PICCON |= cpu_ie
uint8_t get_weekday(struct tm *const _tm)
{
uint8_t weekday;
time_t secs = mktime(_tm);
weekday = (secs / 86400 + 4) % 7;
return weekday;
}
void irtc_write(uint32_t cmd)
{
RTCDAT = cmd;
while (RTCCON & RTC_CON_TRANS_DONE);
}
uint8_t irtc_read(void)
{
RTCDAT = 0x00;
while (RTCCON & RTC_CON_TRANS_DONE);
return (uint8_t)RTCDAT;
}
void irtc_time_write(uint32_t cmd, uint32_t dat)
{
IRTC_ENTER_CRITICAL();
RTCCON |= RTC_CON_CHIP_SELECT;
irtc_write(cmd | RTC_WR);
irtc_write((uint8_t)(dat >> 24));
irtc_write((uint8_t)(dat >> 16));
irtc_write((uint8_t)(dat >> 8));
irtc_write((uint8_t)(dat >> 0));
RTCCON &= ~RTC_CON_CHIP_SELECT;
IRTC_EXIT_CRITICAL();
}
uint32_t irtc_time_read(uint32_t cmd)
{
uint32_t rd_val;
IRTC_ENTER_CRITICAL();
RTCCON |= RTC_CON_CHIP_SELECT;
irtc_write(cmd | RTC_RD);
*((uint8_t *)&rd_val + 3) = irtc_read();
*((uint8_t *)&rd_val + 2) = irtc_read();
*((uint8_t *)&rd_val + 1) = irtc_read();
*((uint8_t *)&rd_val + 0) = irtc_read();
RTCCON &= ~RTC_CON_CHIP_SELECT;
IRTC_EXIT_CRITICAL();
return rd_val;
}
void irtc_sfr_write(uint32_t cmd, uint8_t dat)
{
IRTC_ENTER_CRITICAL();
RTCCON |= RTC_CON_CHIP_SELECT;
irtc_write(cmd | RTC_WR);
irtc_write(dat);
RTCCON &= ~RTC_CON_CHIP_SELECT;
IRTC_EXIT_CRITICAL();
}
uint8_t irtc_sfr_read(uint32_t cmd)
{
uint8_t rd_val;
IRTC_ENTER_CRITICAL();
RTCCON |= RTC_CON_CHIP_SELECT;
irtc_write(cmd | RTC_RD);
rd_val = irtc_read();
RTCCON &= ~RTC_CON_CHIP_SELECT;
IRTC_EXIT_CRITICAL();
}
void hal_rtc_init(void)
{
time_t sec = 0;
struct tm tm_new = {0};
uint8_t temp = irtc_sfr_read(RTCCON0_CMD);
temp &= ~RTC_CON0_XOSC32K_ENABLE;
temp |= RTC_CON0_EXTERNAL_32K;
irtc_sfr_write(RTCCON0_CMD, temp);
temp = irtc_sfr_read(RTCCON2_CMD);
irtc_sfr_write(RTCCON2_CMD, temp | RTC_CON2_32K_SELECT);
temp = irtc_sfr_read(RTCCON0_CMD);
if (temp & BIT(7)) {
temp &= ~BIT(7);
irtc_sfr_write(RTCCON0_CMD, temp); /* First power on */
}
tm_new.tm_mday = 29;
tm_new.tm_mon = 1 - 1;
tm_new.tm_year = 2021 - 1900;
sec = mktime(&tm_new);
irtc_time_write(RTCCNT_CMD, sec);
}
/************** HAL End *******************/
static time_t get_rtc_timestamp(void)
{
time_t sec = 0;
sec = irtc_time_read(RTCCNT_CMD);
LOG_D("get rtc time.");
return sec;
}
static rt_err_t set_rtc_time_stamp(time_t time_stamp)
{
irtc_time_write(RTCCNT_CMD, time_stamp);
return RT_EOK;
}
static void rt_rtc_init(void)
{
hal_rtc_init();
}
static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args)
{
rt_err_t result = RT_EOK;
RT_ASSERT(dev != RT_NULL);
switch (cmd)
{
case RT_DEVICE_CTRL_RTC_GET_TIME:
*(rt_uint32_t *)args = get_rtc_timestamp();
LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);
break;
case RT_DEVICE_CTRL_RTC_SET_TIME:
if (set_rtc_time_stamp(*(rt_uint32_t *)args))
{
result = -RT_ERROR;
}
LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);
break;
}
return result;
}
#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops rtc_ops =
{
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
RT_NULL,
rt_rtc_control
};
#endif
static rt_err_t rt_hw_rtc_register(rt_device_t device, const char *name, rt_uint32_t flag)
{
RT_ASSERT(device != RT_NULL);
rt_rtc_init();
#ifdef RT_USING_DEVICE_OPS
device->ops = &rtc_ops;
#else
device->init = RT_NULL;
device->open = RT_NULL;
device->close = RT_NULL;
device->read = RT_NULL;
device->write = RT_NULL;
device->control = rt_rtc_control;
#endif
device->type = RT_Device_Class_RTC;
device->rx_indicate = RT_NULL;
device->tx_complete = RT_NULL;
device->user_data = RT_NULL;
/* register a character device */
return rt_device_register(device, name, flag);
}
int rt_hw_rtc_init(void)
{
rt_err_t result;
result = rt_hw_rtc_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR);
if (result != RT_EOK)
{
LOG_E("rtc register err code: %d", result);
return result;
}
LOG_D("rtc init success");
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_rtc_init);
#endif /* BSP_USING_ONCHIP_RTC */

View File

@ -11,7 +11,6 @@ Import('rtconfig')
PKGNAME = "ab32vg1_hal"
VERSION = "v1.0.0"
DEPENDS = [""]
#DEPENDS = ["PKG_USING_RW007"]
#---------------------------------------------------------------------------------
# Compile the configuration
@ -35,6 +34,7 @@ DEPENDS = [""]
#
# LINKFLAGS: Link options
#---------------------------------------------------------------------------------
CWD = GetCurrentDir()
SOURCES = Glob("./source/*.c")
LOCAL_CPPPATH = []
@ -48,8 +48,8 @@ ASFLAGS = ""
CPPDEFINES = []
LOCAL_CPPDEFINES = []
LIBS = []
LIBPATH = []
LIBS = ['hal']
LIBPATH = [CWD]
LINKFLAGS = ""

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2020-2021, BLUETRUM Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef AB32VG1_HAL_ADC_H__
#define AB32VG1_HAL_ADC_H__
#include "ab32vg1_hal_def.h"
/**
* @defgroup ADC_channels
* @{
*/
#define ADC_CHANNEL_0 (1u << 0)
#define ADC_CHANNEL_1 (1u << 1)
#define ADC_CHANNEL_2 (1u << 2)
#define ADC_CHANNEL_3 (1u << 3)
#define ADC_CHANNEL_4 (1u << 4)
#define ADC_CHANNEL_5 (1u << 5)
#define ADC_CHANNEL_6 (1u << 6)
#define ADC_CHANNEL_7 (1u << 7)
#define ADC_CHANNEL_8 (1u << 8)
#define ADC_CHANNEL_9 (1u << 9)
#define ADC_CHANNEL_10 (1u << 10)
#define ADC_CHANNEL_11 (1u << 11)
#define ADC_CHANNEL_12 (1u << 12)
#define ADC_CHANNEL_13 (1u << 13)
#define ADC_CHANNEL_14 (1u << 14)
#define ADC_CHANNEL_15 (1u << 15)
/**
* @}
*
*/
/**
* @brief Enable ADC
*
* @param enable
*/
void hal_adc_enable(uint8_t enable);
/**
* @brief Starts conversion of the channels
*
* @param channel @ref ADC_channels
*/
void hal_adc_start(uint32_t channel);
/**
* @brief Poll for conversion complete
*
* @param timeout Timeout value in millisecond
* @return hal_error_t
*/
hal_error_t hal_adc_poll_for_conversion(uint32_t timeout);
#endif

View File

@ -15,6 +15,8 @@
// #define HAL_DAC_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLE
#define HAL_ADC_MODULE_ENABLE
/* Includes */
#ifdef HAL_GPIO_MODULE_ENABLED
@ -45,6 +47,14 @@
#include "ab32vg1_hal_tim.h"
#endif
#ifdef HAL_RTC_MODULE_ENABLE
#include "ab32vg1_hal_rtc.h"
#endif
#ifdef HAL_ADC_MODULE_ENABLE
#include "ab32vg1_hal_adc.h"
#endif
#include <assert.h>
#endif

View File

@ -8,6 +8,17 @@
#define AB32VG1_HAL_GPIO_EX_H__
/* Alternate function */
#define GPIO_AF_MAP_Gx(AF, Gx) ((uint32_t)((Gx) << (AF)))
#define GPIO_AF_MAP_CLR(AF) ((uint32_t)(0xfu << (AF)))
#define GPIO_AF_G1 (1u)
#define GPIO_AF_G2 (2u)
#define GPIO_AF_G3 (3u)
#define GPIO_AF_G4 (4u)
#define GPIO_AF_G5 (5u)
#define GPIO_AF_G6 (6u)
#define GPIO_AF_G7 (7u)
/**
* UART0:
* G1: tx:PA7 rx:PA6
@ -23,16 +34,6 @@
* G2: tx:PA4 rx:PA3
* G3: tx:PF2 rx:map to tx
*/
#define GPIO_AF_MAP_Gx(AF, Gx) ((uint32_t)((Gx) << (AF)))
#define GPIO_AF_MAP_CLR(AF) ((uint32_t)(0xfu << (AF)))
#define GPIO_AF_G1 (1u)
#define GPIO_AF_G2 (2u)
#define GPIO_AF_G3 (3u)
#define GPIO_AF_G4 (4u)
#define GPIO_AF_G5 (5u)
#define GPIO_AF_G6 (6u)
#define GPIO_AF_G7 (7u)
#define UT1RXMAP_AF (28u)
#define UT1TXMAP_AF (24u)
@ -46,26 +47,44 @@
#define UT1RXMAP_TX ((uint32_t)(0x3u << (UT1RXMAP_AF)))
#define UT0RXMAP_TX ((uint32_t)(0x7u << (UT0RXMAP_AF)))
#define GPIO_HSUART_G1
#define GPIO_HSUART_G2
#define GPIO_HSUART_G3
#define GPIO_HSUART_G4
#define GPIO_HSUART_G5
#define GPIO_HSUART_G6
#define GPIO_HSUART_G7
#define GPIO_HSUART_G8
#define GPIO_HSUART_G9
#define GPIO_HSUART_G10
/**
* LPWM3:
* G1: PE7
* G2: PF2
* G3: PA3
*
* LPWM2:
* G1: PE6
* G2: PE0
* G3: PA2
*
* LPWM1:
* G1: PE5
* G2: PB4
* G3: PA1
*
* LPWM0:
* G1: PE4
* G2: PB3
* G3: PA0
*/
#define LPWM3MAP_AF (28u)
#define LPWM2MAP_AF (24u)
#define LPWM1MAP_AF (20u)
#define LPWM0MAP_AF (16u)
#define GPIO_SPI0_G1
#define GPIO_SPI0_G2
#define GPIO_SPI0_G3
#define GPIO_SD0_G1
#define GPIO_SD0_G2
#define GPIO_SD0_G3
#define GPIO_SD0_G4
#define GPIO_SD0_G5
#define GPIO_SD0_G6
/**
* TMR5:
* G1: PE1 PE2 PE3
*
* TMR4:
* G1: PA5 PA6 PA7
*
* TMR3:
* G1: PB0 PB1 PB2
*/
#define TMR5MAP_AF (16u)
#define TMR4MAP_AF (12u)
#define TMR3MAP_AF ( 8u)
#endif

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020-2020, BLUETRUM Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef AB32VG1_HAL_RTC_H__
#define AB32VG1_HAL_RTC_H__
#define RTC_BASE ((hal_sfr_t)&RTCCON)
enum
{
RTCxCON,
RTCxDAT,
RTCxCPND = 3,
};
// RTCCON
#define RTC_CON_VUSB_OLINE (0x1u << 20) /*!< VUSB online state */
#define RTC_CON_WK_PIN_STATE (0x1u << 19) /*!< RTC wakeup pin state */
#define RTC_CON_1S_PEND (0x1u << 18) /*!< RTC 1s pending */
#define RTC_CON_ALM_PEND (0x1u << 17) /*!< RTC alarm pending */
#define RTC_CON_TRANS_DONE (0x1u << 16) /*!< RTC trans done */
#define RTC_CON_ALM_WK_ENABLE (0x1u << 8) /*!< RTC alarm wakeup enable */
#define RTC_CON_1S_WK_ENABLE (0x1u << 7) /*!< RTC 1s wakeup enable */
#define RTC_CON_VUSB_RST_ENABLE (0x1u << 6) /*!< VUSB insert reset system enable */
#define RTC_CON_WK_RST_ENABLE (0x1u << 5) /*!< RTC wakeup power down mode reset \
system enable */
#define RTC_CON_ALM_INTERRUPT (0x1u << 4) /*!< RTC alarm interrupt enable */
#define RTC_CON_1S_INTERRUPT (0x1u << 3) /*!< RTC 1s interrupt enable */
#define RTC_CON_BAUD_SELECT (0x3u << 1) /*!< Increase clock selection */
#define RTC_CON_CHIP_SELECT (0x1u << 0) /*!< RTC chip select */
// RTCCON0
#define RTC_CON0_PWRUP_FIRST (0x01u << 7) /*!< RTC first power up flag */
#define RTC_CON0_EXTERNAL_32K (0x01u << 6) /*!< External 32K select */
#define RTC_CON0_VDD_ENABLE (0x01u << 5) /*!< RTC VDD12 enable */
#define RTC_CON0_BG_ENABLE (0x01u << 4) /*!< BG enable */
#define RTC_CON0_LVD_OUTPUT_ENABLE (0x01u << 3) /*!< LVD output enable */
#define RTC_CON0_LVD_ENABLE (0x01u << 2) /*!< LVD enbale */
#define RTC_CON0_XOSC32K_ENABLE (0x01u << 1) /*!< XOSC32K enable */
#define RTC_CON0_RCOSC_ENABLE (0x01u << 0) /*!< RCOSC enable */
// RTCCON2
#define RTC_CON2_32K_SELECT (0x01u << 7) /*!< 32K osc select */
#endif

View File

@ -14,23 +14,23 @@
/*!< Interrupt Number Definition */
typedef enum
{
IRQ_SW_VECTOR = 2,
IRQ_TMR0_VECTOR = 3,
IRQ_TMR1_VECTOR = 4,
IRQ_TMR2_4_5_VECTOR = 5, /*!< Timer 2, 4 and 5 Interrupt */
IRQ_IRRX_VECTOR = 6, /*!< Timer 3 and IR receiver Interrupt */
IRQ_USB_VECTOR = 7,
IRQ_SD_VECTOR = 8,
IRQ_AUBUF0_1_VECTOR = 9, /*!< Audio buffer 0 and 1 Interrupt */
IRQ_SDADC_VECTOR = 10,
IRQ_AUDEC_VECTOR = 11, /*!< Audio codec, SBC encode and AEC FFT Interrupt */
IRQ_SRC_VECTOR = 12, /*!< SRC, PLC and CVSD Interrupt */
IRQ_FM_SPDIF_VECTOR = 13, /*!< FM TX, RX and SPDIF RX Interrupt */
IRQ_UART0_2_VECTOR = 14, /*!< UART 0 to 2 Interrupt */
IRQ_HSUART_VECTOR = 15,
IRQ_RTC_VECTOR = 16, /*!< RTC, LVD and WDT Interrupt */
IRQ_I2S_VECTOR = 17,
IRQ_TOTAL_NUM = 23,
IRQ_SW_VECTOR = 2,
IRQ_TMR0_VECTOR = 3,
IRQ_TMR1_VECTOR = 4,
IRQ_TMR2_4_5_VECTOR = 5, /*!< Timer 2, 4 and 5 Interrupt */
IRQ_IRRX_VECTOR = 6, /*!< Timer 3 and IR receiver Interrupt */
IRQ_USB_VECTOR = 7,
IRQ_SD_VECTOR = 8,
IRQ_AUBUF0_1_VECTOR = 9, /*!< Audio buffer 0 and 1 Interrupt */
IRQ_SDADC_VECTOR = 10,
IRQ_AUDEC_VECTOR = 11, /*!< Audio codec, SBC encode and AEC FFT Interrupt */
IRQ_SRC_VECTOR = 12, /*!< SRC, PLC and CVSD Interrupt */
IRQ_FM_SPDIF_VECTOR = 13, /*!< FM TX, RX and SPDIF RX Interrupt */
IRQ_UART0_2_VECTOR = 14, /*!< UART 0 to 2 Interrupt */
IRQ_HSUART_VECTOR = 15,
IRQ_RTC_VECTOR = 16, /*!< RTC, LVD and WDT Interrupt */
IRQ_I2S_VECTOR = 17,
IRQ_TOTAL_NUM = 23,
} irq_type;
#endif // __ASSEMBLER__

View File

@ -19,7 +19,7 @@ source "$RTT_DIR/Kconfig"
source "$RTT_DIR/libcpu/mips/common/Kconfig"
source "$PKGS_DIR/Kconfig"
config SOC_1C300
config SOC_LS1C300
bool
select RT_USING_COMPONENTS_INIT
select RT_USING_USER_MAIN

View File

@ -161,7 +161,7 @@
/* samples: kernel and components samples */
#define SOC_1C300
#define SOC_LS1C300
#define RT_LS1C_BAICAIBOARD
#define RT_USING_SELF_BOOT
#define RT_SELF_BOOT_DEBUG

View File

@ -29,4 +29,13 @@ config SOC_LS2K1000
select RT_USING_USER_MAIN
select RT_USING_DEVICE
default y
if RT_USING_SERIAL
config RT_USING_UART0
bool "Using RT_USING_UART0"
default y
config RT_USING_UART4
bool "Using RT_USING_UART4"
default y
endif

View File

@ -90,7 +90,7 @@ void rt_hw_board_init(void)
/* init hardware UART device */
rt_hw_uart_init();
/* set console device */
rt_console_set_device("uart0");
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#ifdef RT_USING_HEAP

View File

@ -6,6 +6,7 @@
* Change Logs:
* Date Author Notes
* 2020-10-28 0xcccccccccccc Initial Version
* 2021-01-17 0xcccccccccccc Bug Fixed : clock division cannot been adjusted as expected due to wrong register configuration.
*/
/**
* @addtogroup ls2k
@ -21,11 +22,11 @@
#ifdef RT_USING_SPI
static void spi_init(uint8_t spre_spr, uint8_t copl, uint8_t cpha)
{
SET_SPI(SPSR, 0xc0 | (spre_spr & 0b00000011));
SET_SPI(SPSR, 0xc0);
SET_SPI(PARAM, 0x40);
SET_SPI(PARAM2, 0x01);
SET_SPI(SPER, (spre_spr & 0b00001100) >> 2);
SET_SPI(SPCR, 0x50 | copl << 3 | cpha << 2);
SET_SPI(SPCR, 0x50 | copl << 3 | cpha << 2 | (spre_spr & 0b00000011));
SET_SPI(SOFTCS, 0xff);
}

View File

@ -156,26 +156,32 @@ struct rt_serial_device serial, serial4;
void rt_hw_uart_init(void)
{
struct rt_uart_ls2k *uart, *uart4;
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
uart = &uart_dev0;
uart4 = &uart_dev4;
#ifdef RT_USING_UART0
struct rt_uart_ls2k *uart0;
uart0 = &uart_dev0;
serial.ops = &ls2k_uart_ops;
serial.config = config_uart0;
serial4.ops = &ls2k_uart_ops;
serial4.config = config;
rt_hw_interrupt_install(uart->IRQ, uart_irq_handler, &serial, "UART0");
rt_hw_interrupt_install(uart4->IRQ, uart_irq_handler, &serial4, "UART4");
rt_hw_interrupt_install(uart0->IRQ, uart_irq_handler, &serial, "UART0");
/* register UART device */
rt_hw_serial_register(&serial,
"uart0",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
uart);
uart0);
#endif
#ifdef RT_USING_UART4
struct rt_uart_ls2k *uart4;
uart4 = &uart_dev4;
serial4.ops = &ls2k_uart_ops;
serial4.config = config;
rt_hw_interrupt_install(uart4->IRQ, uart_irq_handler, &serial4, "UART4");
rt_hw_serial_register(&serial4,
"uart4",
RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
&uart_dev4);
#endif
}
/*@}*/

View File

@ -37,7 +37,7 @@
#define RT_USING_DEVICE
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 256
#define RT_CONSOLE_DEVICE_NAME "uart"
#define RT_CONSOLE_DEVICE_NAME "uart0"
#define RT_VER_NUM 0x40003
#define ARCH_CPU_64BIT
#define ARCH_MIPS64
@ -82,6 +82,8 @@
#define RT_DFS_ELM_WORD_ACCESS
#define RT_DFS_ELM_USE_LFN_3
#define RT_DFS_ELM_USE_LFN 3
#define RT_DFS_ELM_LFN_UNICODE_0
#define RT_DFS_ELM_LFN_UNICODE 0
#define RT_DFS_ELM_MAX_LFN 255
#define RT_DFS_ELM_DRIVES 9
#define RT_DFS_ELM_MAX_SECTOR_SIZE 512
@ -114,6 +116,7 @@
/* Socket abstraction layer */
#define RT_USING_SAL
#define SAL_INTERNET_CHECK
/* protocol stack implement */
@ -220,9 +223,6 @@
/* system packages */
/* Micrium: Micrium software products porting for RT-Thread */
/* peripheral libraries and drivers */
@ -231,9 +231,8 @@
/* samples: kernel and components samples */
/* games: games run on RT-Thread console */
#define SOC_LS2K1000
#define RT_USING_UART0
#define RT_USING_UART4
#endif

View File

@ -17,11 +17,12 @@ extern int Image$$RW_IRAM1$$ZI$$Limit;
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
extern int __bss_end__;
#define HEAP_BEGIN ((void *)&__bss_end__)
#endif
#define HEAP_END (0x20000000 + 64*1024)
#define HEAP_SIZE 16*1024
#define HEAP_END (HEAP_BEGIN + HEAP_SIZE)
void rt_hw_board_init(void);

View File

@ -0,0 +1,16 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x80000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x10000
CODE_RAM (rwx) : ORIGIN = 0x800000, LENGTH = 0x10000
}
INCLUDE "packages/nrfx-v2.1.0/mdk/nrf_common.ld"

View File

@ -43,7 +43,7 @@ if PLATFORM == 'gcc':
DEVICE = ' -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections'
CFLAGS = DEVICE
AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp'
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-nrf52832.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds'
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds'
CPATH = ''
LPATH = ''

View File

@ -17,11 +17,12 @@ extern int Image$$RW_IRAM1$$ZI$$Limit;
#pragma section="CSTACK"
#define HEAP_BEGIN (__segment_end("CSTACK"))
#else
extern int __bss_end;
#define HEAP_BEGIN ((void *)&__bss_end)
extern int __bss_end__;
#define HEAP_BEGIN ((void *)&__bss_end__)
#endif
#define HEAP_END (0x20000000 + 64*1024)
#define HEAP_SIZE 16*1024
#define HEAP_END (HEAP_BEGIN + HEAP_SIZE)
void rt_hw_board_init(void);

View File

@ -0,0 +1,16 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x100000
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000
CODE_RAM (rwx) : ORIGIN = 0x800000, LENGTH = 0x10000
}
INCLUDE "packages/nrfx-v2.1.0/mdk/nrf_common.ld"

View File

@ -43,7 +43,7 @@ if PLATFORM == 'gcc':
DEVICE = ' -mcpu=cortex-m4 -mthumb -ffunction-sections -fdata-sections'
CFLAGS = DEVICE
AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp'
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread-nrf52832.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds'
LFLAGS = DEVICE + ' -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds'
CPATH = ''
LPATH = ''

View File

@ -44,8 +44,10 @@ static rt_uint32_t nu_crc_run(
{
uint32_t u32CalChecksum = 0;
uint32_t i = 0;
rt_err_t result;
rt_mutex_take(&s_CRC_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_CRC_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Configure CRC controller */
CRC_Open(u32OpMode, u32Attr, u32Seed, CRC_CPU_WDATA_8);
@ -85,16 +87,22 @@ static rt_uint32_t nu_crc_run(
/* Get checksum value */
u32CalChecksum = CRC_GetChecksum();
rt_mutex_release(&s_CRC_mutex);
result = rt_mutex_release(&s_CRC_mutex);
RT_ASSERT(result == RT_EOK);
return u32CalChecksum;
}
rt_err_t nu_crc_init(void)
{
rt_err_t result;
SYS_ResetModule(CRC_RST);
rt_mutex_init(&s_CRC_mutex, NU_CRYPTO_CRC_NAME, RT_IPC_FLAG_FIFO);
result = rt_mutex_init(&s_CRC_mutex, NU_CRYPTO_CRC_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}

View File

@ -81,6 +81,8 @@ static volatile int s_SHA_done;
static rt_err_t nu_crypto_init(void)
{
rt_err_t result;
/* Enable Crypto engine interrupt */
NVIC_EnableIRQ(CRPT_IRQn);
@ -89,12 +91,19 @@ static rt_err_t nu_crypto_init(void)
SHA_ENABLE_INT(CRPT);
//init cipher mutex
rt_mutex_init(&s_AES_mutex, NU_HWCRYPTO_AES_NAME, RT_IPC_FLAG_FIFO);
rt_mutex_init(&s_TDES_mutex, NU_HWCRYPTO_TDES_NAME, RT_IPC_FLAG_FIFO);
rt_mutex_init(&s_SHA_mutex, NU_HWCRYPTO_SHA_NAME, RT_IPC_FLAG_FIFO);
result = rt_mutex_init(&s_AES_mutex, NU_HWCRYPTO_AES_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
result = rt_mutex_init(&s_TDES_mutex, NU_HWCRYPTO_TDES_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
result = rt_mutex_init(&s_SHA_mutex, NU_HWCRYPTO_SHA_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
#if !defined(BSP_USING_TRNG)
PRNG_ENABLE_INT(CRPT);
rt_mutex_init(&s_PRNG_mutex, NU_HWCRYPTO_PRNG_NAME, RT_IPC_FLAG_FIFO);
result = rt_mutex_init(&s_PRNG_mutex, NU_HWCRYPTO_PRNG_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
#endif
return RT_EOK;
@ -146,6 +155,8 @@ static rt_err_t nu_aes_crypt_run(
uint32_t u32DataLen
)
{
rt_err_t result;
uint32_t au32SwapKey[8];
uint32_t au32SwapIV[4];
@ -171,7 +182,8 @@ static rt_err_t nu_aes_crypt_run(
au32SwapIV[2] = nu_get32_be(&pu8IV[8]);
au32SwapIV[3] = nu_get32_be(&pu8IV[12]);
rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
//Using Channel 0
AES_Open(CRPT, 0, bEncrypt, u32OpMode, u32KeySize, AES_IN_OUT_SWAP);
@ -186,7 +198,8 @@ static rt_err_t nu_aes_crypt_run(
AES_Start(CRPT, 0, CRYPTO_DMA_ONE_SHOT);
while (!s_AES_done) {};
rt_mutex_release(&s_AES_mutex);
result = rt_mutex_release(&s_AES_mutex);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
@ -195,19 +208,26 @@ static rt_err_t nu_aes_crypt_run(
//Using PRNG instead of TRNG
static void nu_prng_open(uint32_t u32Seed)
{
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
rt_err_t result;
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
//Open PRNG 64 bits. But always return 32 bits
PRNG_Open(CRPT, PRNG_KEY_SIZE_64, PRNG_SEED_RELOAD, u32Seed);
rt_mutex_release(&s_PRNG_mutex);
result = rt_mutex_release(&s_PRNG_mutex);
RT_ASSERT(result == RT_EOK);
}
static rt_uint32_t nu_prng_run(void)
{
rt_err_t result;
uint32_t au32RNGValue[2];
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
s_PRNG_done = 0;
PRNG_Start(CRPT);
@ -215,7 +235,9 @@ static rt_uint32_t nu_prng_run(void)
PRNG_Read(CRPT, au32RNGValue);
rt_mutex_release(&s_PRNG_mutex);
result = rt_mutex_release(&s_PRNG_mutex);
RT_ASSERT(result == RT_EOK);
return au32RNGValue[0];
}
@ -356,6 +378,8 @@ static rt_err_t nu_des_crypt_run(
uint32_t u32DataLen
)
{
rt_err_t result;
uint32_t au32SwapKey[3][2];
uint32_t au32SwapIV[2];
@ -373,7 +397,8 @@ static rt_err_t nu_des_crypt_run(
au32SwapIV[0] = nu_get32_be(&pu8IV[0]);
au32SwapIV[1] = nu_get32_be(&pu8IV[4]);
rt_mutex_take(&s_TDES_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_TDES_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
//Using Channel 0
TDES_Open(CRPT, 0, bEncrypt, (u32OpMode & CRPT_TDES_CTL_TMODE_Msk), u32KeySize, u32OpMode, TDES_IN_OUT_WHL_SWAP);
@ -388,7 +413,8 @@ static rt_err_t nu_des_crypt_run(
TDES_Start(CRPT, 0, CRYPTO_DMA_ONE_SHOT);
while (!s_TDES_done) {};
rt_mutex_release(&s_TDES_mutex);
result = rt_mutex_release(&s_TDES_mutex);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
@ -534,7 +560,10 @@ static rt_err_t nu_sha_hash_run(
uint32_t u32DataLen
)
{
rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
rt_err_t result;
result = rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
uint8_t *pu8SrcAddr = (uint8_t *)pu8InData;
uint32_t u32CopyLen = 0;
@ -574,7 +603,10 @@ static rt_err_t nu_sha_hash_run(
if (psSHACtx->pu8SHATempBuf == RT_NULL)
{
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return -RT_ENOMEM;
}
@ -602,7 +634,10 @@ static rt_err_t nu_sha_hash_run(
if (psSHACtx->pu8SHATempBuf == RT_NULL)
{
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return -RT_ENOMEM;
}
@ -613,7 +648,8 @@ static rt_err_t nu_sha_hash_run(
psSHACtx->u32SHATempBufLen += u32DataLen;
}
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}

View File

@ -242,6 +242,8 @@ static void link_monitor(void *param)
static rt_err_t nu_emac_init(rt_device_t dev)
{
rt_err_t result;
nu_emac_t psNuEMAC = (nu_emac_t)dev;
EMAC_Close();
@ -254,9 +256,12 @@ static rt_err_t nu_emac_init(rt_device_t dev)
NVIC_SetPriority(EMAC_RX_IRQn, 1);
NVIC_EnableIRQ(EMAC_RX_IRQn);
rt_sem_init(&psNuEMAC->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
result = rt_sem_init(&psNuEMAC->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
result = rt_thread_init(&eth_tid, "eth", link_monitor, (void *)psNuEMAC, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
RT_ASSERT(result == RT_EOK);
rt_thread_init(&eth_tid, "eth", link_monitor, (void *)psNuEMAC, eth_stack, sizeof(eth_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
rt_thread_startup(&eth_tid);
#if defined(LWIP_IPV4) && defined(LWIP_IGMP)
@ -310,6 +315,7 @@ static rt_err_t nu_emac_control(rt_device_t dev, int cmd, void *args)
static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
{
rt_err_t result;
nu_emac_t psNuEMAC = (nu_emac_t)dev;
struct pbuf *q;
rt_uint32_t offset = 0;
@ -319,14 +325,15 @@ static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
/* Get free TX buffer */
if (buf == RT_NULL)
{
rt_sem_control(&psNuEMAC->eth_sem, RT_IPC_CMD_RESET, 0);
result = rt_sem_control(&psNuEMAC->eth_sem, RT_IPC_CMD_RESET, 0);
RT_ASSERT(result == RT_EOK);
EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk);
EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
do
{
rt_sem_take(&psNuEMAC->eth_sem, 1);
while (rt_sem_take(&psNuEMAC->eth_sem, 10) != RT_EOK) ;
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf();
}
while (buf == RT_NULL);
@ -440,8 +447,11 @@ void EMAC_TX_IRQHandler(void)
/* Wake-up suspended process to send */
if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk))
{
rt_err_t result;
EMAC_DISABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
rt_sem_release(&nu_emac_dev.eth_sem);
result = rt_sem_release(&nu_emac_dev.eth_sem);
RT_ASSERT(result == RT_EOK);
}
if (EMAC_GET_INT_FLAG(EMAC, EMAC_INTSTS_TXBEIF_Msk))

View File

@ -228,41 +228,4 @@ int rt_hw_epwm_init(void)
INIT_DEVICE_EXPORT(rt_hw_epwm_init);
#ifdef RT_USING_FINSH
#include <finsh.h>
#ifdef FINSH_USING_MSH
static int pwm_get(int argc, char **argv)
{
int result = 0;
struct rt_device_pwm *device = RT_NULL;
struct rt_pwm_configuration configuration = {0};
if (argc != 3)
{
rt_kprintf("Usage: pwm_get pwm1 1\n");
result = -RT_ERROR;
goto _exit;
}
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
if (!device)
{
result = -RT_EIO;
goto _exit;
}
configuration.channel = atoi(argv[2]);
result = rt_device_control(&device->parent, PWM_CMD_GET, &configuration);
_exit:
return result;
}
MSH_CMD_EXPORT(pwm_get, pwm_get epwm1 1);
#endif /* FINSH_USING_MSH */
#endif /* RT_USING_FINSH */
#endif

View File

@ -54,10 +54,15 @@ const struct fal_flash_dev Onchip_ldrom_flash = { "OnChip_LDROM", FMC_LDROM_BASE
int nu_fmc_read(long addr, uint8_t *buf, size_t size)
{
rt_err_t result;
size_t read_size = 0;
uint32_t addr_end = addr + size;
uint32_t isp_rdata = 0;
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
SYS_UnlockReg();
if (NU_GET_LSB2BIT(addr))
@ -87,7 +92,9 @@ int nu_fmc_read(long addr, uint8_t *buf, size_t size)
}
SYS_LockReg();
rt_mutex_release(g_mutex_fmc);
result = rt_mutex_release(g_mutex_fmc);
RT_ASSERT(result == RT_EOK);
return read_size;
}
@ -97,8 +104,11 @@ int nu_fmc_write(long addr, const uint8_t *buf, size_t size)
size_t write_size = 0;
uint32_t addr_end = addr + size;
uint32_t isp_rdata = 0;
rt_err_t result;
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
SYS_UnlockReg();
if (addr < FMC_APROM_END)
@ -144,9 +154,12 @@ int nu_fmc_write(long addr, const uint8_t *buf, size_t size)
FMC_DISABLE_AP_UPDATE();
FMC_DISABLE_LD_UPDATE();
Exit2:
SYS_LockReg();
rt_mutex_release(g_mutex_fmc);
result = rt_mutex_release(g_mutex_fmc);
RT_ASSERT(result == RT_EOK);
return write_size;
@ -157,12 +170,12 @@ int nu_fmc_erase(long addr, size_t size)
size_t erased_size = 0;
uint32_t addrptr;
uint32_t addr_end = addr + size;
rt_err_t result;
#if defined(NU_SUPPORT_NONALIGN)
uint8_t *page_sdtemp = RT_NULL;
uint8_t *page_edtemp = RT_NULL;
addrptr = addr & (FMC_FLASH_PAGE_SIZE - 1);
if (addrptr)
{
@ -205,7 +218,9 @@ int nu_fmc_erase(long addr, size_t size)
}
#endif
rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
result = rt_mutex_take(g_mutex_fmc, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
SYS_UnlockReg();
if (addr <= FMC_APROM_END)
@ -233,7 +248,9 @@ Exit1:
FMC_DISABLE_LD_UPDATE();
Exit2:
SYS_LockReg();
rt_mutex_release(g_mutex_fmc);
result = rt_mutex_release(g_mutex_fmc);
RT_ASSERT(result == RT_EOK);
#if defined(NU_SUPPORT_NONALIGN)
@ -315,6 +332,7 @@ static int nu_fmc_init(void)
SYS_LockReg();
g_mutex_fmc = rt_mutex_create("nu_fmc_lock", RT_IPC_FLAG_FIFO);
RT_ASSERT(g_mutex_fmc != RT_NULL);
/* PKG_USING_FAL */
#if defined(PKG_USING_FAL)

View File

@ -256,11 +256,13 @@ void nu_pdma_channel_terminate(int i32ChannID)
int i;
uint32_t u32EnabledChans;
int ch_mask = 0;
rt_err_t result;
if (!(nu_pdma_chn_mask & (1 << i32ChannID)))
goto exit_pdma_channel_terminate;
rt_mutex_take(g_mutex_res, RT_WAITING_FOREVER);
result = rt_mutex_take(g_mutex_res, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
// Suspend all channels.
u32EnabledChans = nu_pdma_chn_mask & NU_PDMA_CH_Msk;
@ -299,7 +301,8 @@ void nu_pdma_channel_terminate(int i32ChannID)
u32EnabledChans &= ~ch_mask;
}
rt_mutex_release(g_mutex_res);
result = rt_mutex_release(g_mutex_res);
RT_ASSERT(result == RT_EOK);
exit_pdma_channel_terminate:
@ -552,7 +555,7 @@ rt_err_t nu_pdma_desc_setup(int i32ChannID, nu_pdma_desc_t dma_desc, uint32_t u3
goto exit_nu_pdma_desc_setup;
else if ((u32AddrSrc % (u32DataWidth / 8)) || (u32AddrDst % (u32DataWidth / 8)))
goto exit_nu_pdma_desc_setup;
else if ( i32TransferCnt > NU_PDMA_MAX_TXCNT )
else if (i32TransferCnt > NU_PDMA_MAX_TXCNT)
goto exit_nu_pdma_desc_setup;
psPeriphCtl = &nu_pdma_chn_arr[i32ChannID - NU_PDMA_CH_Pos].m_spPeripCtl;
@ -625,11 +628,13 @@ static void nu_pdma_sgtbls_token_free(nu_pdma_desc_t psSgtbls)
rt_err_t nu_pdma_sgtbls_allocate(nu_pdma_desc_t *ppsSgtbls, int num)
{
int i, j, idx;
rt_err_t result;
RT_ASSERT(ppsSgtbls != NULL);
RT_ASSERT(num <= NU_PDMA_SG_TBL_MAXSIZE);
rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
result = rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
for (i = 0; i < num; i++)
{
@ -644,7 +649,8 @@ rt_err_t nu_pdma_sgtbls_allocate(nu_pdma_desc_t *ppsSgtbls, int num)
ppsSgtbls[i] = (nu_pdma_desc_t)&nu_pdma_sgtbl_arr[idx];
}
rt_mutex_release(g_mutex_sg);
result = rt_mutex_release(g_mutex_sg);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
@ -660,18 +666,22 @@ fail_nu_pdma_sgtbls_allocate:
ppsSgtbls[j] = NULL;
}
rt_mutex_release(g_mutex_sg);
result = rt_mutex_release(g_mutex_sg);
RT_ASSERT(result == RT_EOK);
return -RT_ERROR;
}
void nu_pdma_sgtbls_free(nu_pdma_desc_t *ppsSgtbls, int num)
{
int i;
rt_err_t result;
RT_ASSERT(ppsSgtbls != NULL);
RT_ASSERT(num <= NU_PDMA_SG_TBL_MAXSIZE);
rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
result = rt_mutex_take(g_mutex_sg, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
for (i = 0; i < num; i++)
{
@ -682,7 +692,8 @@ void nu_pdma_sgtbls_free(nu_pdma_desc_t *ppsSgtbls, int num)
ppsSgtbls[i] = NULL;
}
rt_mutex_release(g_mutex_sg);
result = rt_mutex_release(g_mutex_sg);
RT_ASSERT(result == RT_EOK);
}
static rt_err_t nu_pdma_sgtbls_valid(nu_pdma_desc_t head)
@ -870,6 +881,7 @@ static void nu_pdma_memfun_actor_init(void)
if (-(RT_ERROR) != (nu_pdma_memfun_actor_arr[i].m_i32ChannID = nu_pdma_channel_allocate(PDMA_MEM)))
{
nu_pdma_memfun_actor_arr[i].m_psSemMemFun = rt_sem_create("memactor_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(nu_pdma_memfun_actor_arr[i].m_psSemMemFun != RT_NULL);
}
else
break;
@ -878,16 +890,23 @@ static void nu_pdma_memfun_actor_init(void)
{
nu_pdma_memfun_actor_maxnum = i;
nu_pdma_memfun_actor_mask = ~(((1 << i) - 1));
nu_pdma_memfun_actor_pool_sem = rt_sem_create("mempool_sem", nu_pdma_memfun_actor_maxnum, RT_IPC_FLAG_FIFO);
RT_ASSERT(nu_pdma_memfun_actor_pool_sem != RT_NULL);
nu_pdma_memfun_actor_pool_lock = rt_mutex_create("mempool_lock", RT_IPC_FLAG_FIFO);
RT_ASSERT(nu_pdma_memfun_actor_pool_lock != RT_NULL);
}
}
static void nu_pdma_memfun_cb(void *pvUserData, uint32_t u32Events)
{
rt_err_t result;
nu_pdma_memfun_actor_t psMemFunActor = (nu_pdma_memfun_actor_t)pvUserData;
psMemFunActor->m_u32Result = u32Events;
rt_sem_release(psMemFunActor->m_psSemMemFun);
result = rt_sem_release(psMemFunActor->m_psSemMemFun);
RT_ASSERT(result == RT_EOK);
}
static int nu_pdma_memfun_employ(void)
@ -897,7 +916,10 @@ static int nu_pdma_memfun_employ(void)
/* Headhunter */
if (nu_pdma_memfun_actor_pool_sem && (rt_sem_take(nu_pdma_memfun_actor_pool_sem, RT_WAITING_FOREVER) == RT_EOK))
{
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
rt_err_t result;
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Find the position of first '0' in nu_pdma_memfun_actor_mask. */
idx = nu_cto(nu_pdma_memfun_actor_mask);
if (idx != 32)
@ -908,7 +930,8 @@ static int nu_pdma_memfun_employ(void)
{
idx = -1;
}
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
RT_ASSERT(result == RT_EOK);
}
return idx;
@ -924,6 +947,8 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
while (1)
{
rt_err_t result;
/* Employ actor */
if ((idx = nu_pdma_memfun_employ()) < 0)
continue;
@ -952,7 +977,8 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
0);
/* Wait it done. */
rt_sem_take(psMemFunActor->m_psSemMemFun, RT_WAITING_FOREVER);
result = rt_sem_take(psMemFunActor->m_psSemMemFun, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Give result if get NU_PDMA_EVENT_TRANSFER_DONE.*/
if (psMemFunActor->m_u32Result & NU_PDMA_EVENT_TRANSFER_DONE)
@ -976,12 +1002,16 @@ static rt_size_t nu_pdma_memfun(void *dest, void *src, uint32_t u32DataWidth, un
}
while (u32TransferCnt > 0);
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
nu_pdma_memfun_actor_mask &= ~(1 << idx);
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
RT_ASSERT(result == RT_EOK);
/* Fire actor */
rt_sem_release(nu_pdma_memfun_actor_pool_sem);
result = rt_sem_release(nu_pdma_memfun_actor_pool_sem);
RT_ASSERT(result == RT_EOK);
break;
}

View File

@ -61,7 +61,7 @@ static struct nu_spi nu_qspi_arr [] =
.name = "qspi0",
.spi_base = (SPI_T *)QSPI0,
#if defined(BSP_USING_QSPI_PDMA)
#if defined(BSP_USING_SPI_PDMA)
#if defined(BSP_USING_QSPI0_PDMA)
.pdma_perp_tx = PDMA_QSPI0_TX,
.pdma_perp_rx = PDMA_QSPI0_RX,
@ -77,7 +77,7 @@ static struct nu_spi nu_qspi_arr [] =
.name = "qspi1",
.spi_base = (SPI_T *)QSPI1,
#if defined(BSP_USING_QSPI_PDMA)
#if defined(BSP_USING_SPI_PDMA)
#if defined(BSP_USING_QSPI1_PDMA)
.pdma_perp_tx = PDMA_QSPI1_TX,
.pdma_perp_rx = PDMA_QSPI1_RX,

View File

@ -270,11 +270,13 @@ static rt_size_t nu_sdh_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_siz
{
rt_uint32_t ret = 0;
nu_sdh_t sdh = (nu_sdh_t)dev;
rt_err_t result;
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Check alignment. */
if (((uint32_t)buffer & 0x03) != 0)
@ -315,7 +317,8 @@ exit_nu_sdh_read:
sdh->pbuf = RT_NULL;
}
rt_sem_release(&sdh->lock);
result = rt_sem_release(&sdh->lock);
RT_ASSERT(result == RT_EOK);
if (ret == Successful)
return blk_nb;
@ -329,11 +332,13 @@ static rt_size_t nu_sdh_write(rt_device_t dev, rt_off_t pos, const void *buffer,
{
rt_uint32_t ret = 0;
nu_sdh_t sdh = (nu_sdh_t)dev;
rt_err_t result;
RT_ASSERT(dev != RT_NULL);
RT_ASSERT(buffer != RT_NULL);
rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
result = rt_sem_take(&sdh->lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Check alignment. */
if (((uint32_t)buffer & 0x03) != 0)
@ -372,7 +377,8 @@ exit_nu_sdh_write:
sdh->pbuf = RT_NULL;
}
rt_sem_release(&sdh->lock);
result = rt_sem_release(&sdh->lock);
RT_ASSERT(result == RT_EOK);
if (ret == Successful) return blk_nb;
@ -427,11 +433,13 @@ static int rt_hw_sdh_init(void)
/* Private */
nu_sdh_arr[i].dev.user_data = (void *)&nu_sdh_arr[i];
rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
ret = rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
nu_sdh_arr[i].pbuf = RT_NULL;
ret = rt_device_register(&nu_sdh_arr[i].dev, nu_sdh_arr[i].name, flags);
RT_ASSERT(ret == RT_EOK);
}
@ -620,7 +628,11 @@ static void sdh_hotplugger(void *param)
int mnt_init_sdcard_hotplug(void)
{
rt_thread_init(&sdh_tid, "hotplug", sdh_hotplugger, NULL, sdh_stack, sizeof(sdh_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
rt_err_t result;
result = rt_thread_init(&sdh_tid, "hotplug", sdh_hotplugger, NULL, sdh_stack, sizeof(sdh_stack), RT_THREAD_PRIORITY_MAX - 2, 10);
RT_ASSERT(result == RT_EOK);
rt_thread_startup(&sdh_tid);
return 0;

View File

@ -241,11 +241,13 @@ exit_nu_spi_bus_configure:
#if defined(BSP_USING_SPI_PDMA)
static void nu_pdma_spi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
{
rt_err_t result;
struct nu_spi *spi_bus = (struct nu_spi *)pvUserData;
RT_ASSERT(spi_bus != RT_NULL);
rt_sem_release(spi_bus->m_psSemBus);
result = rt_sem_release(spi_bus->m_psSemBus);
RT_ASSERT(result == RT_EOK);
}
static rt_err_t nu_pdma_spi_rx_config(struct nu_spi *spi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
{
@ -362,7 +364,8 @@ static rt_size_t nu_spi_pdma_transmit(struct nu_spi *spi_bus, const uint8_t *sen
SPI_TRIGGER_TX_RX_PDMA(spi_base);
/* Wait RX-PDMA transfer done */
rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
result = rt_sem_take(spi_bus->m_psSemBus, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Stop TX/RX DMA transfer. */
SPI_DISABLE_TX_RX_PDMA(spi_base);
@ -391,6 +394,7 @@ rt_err_t nu_hw_spi_pdma_allocate(struct nu_spi *spi_bus)
}
spi_bus->m_psSemBus = rt_sem_create("spibus_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(spi_bus->m_psSemBus != RT_NULL);
return RT_EOK;

View File

@ -243,10 +243,11 @@ exit_nu_spii2s_capacity_check:
static rt_err_t nu_spii2s_dai_setup(nu_i2s_t psNuSPII2s, struct rt_audio_configure *pconfig)
{
rt_err_t result = RT_EOK;
nu_acodec_ops_t pNuACodecOps = RT_NULL;
nu_acodec_ops_t pNuACodecOps;
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
pNuACodecOps = psNuSPII2s->AcodecOps;
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
/* Open SPII2S */
if (nu_spii2s_capacity_check(pconfig) == RT_TRUE)
@ -283,7 +284,7 @@ static rt_err_t nu_spii2s_dai_setup(nu_i2s_t psNuSPII2s, struct rt_audio_configu
/* Set MCLK and enable MCLK */
SPII2S_EnableMCLK(spii2s_base, __HXT);
/* Set unmute */
/* Set un-mute */
if (pNuACodecOps->nu_acodec_mixer_control)
pNuACodecOps->nu_acodec_mixer_control(AUDIO_MIXER_MUTE, RT_FALSE);
}
@ -298,14 +299,11 @@ exit_nu_spii2s_dai_setup:
static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
rt_err_t result = RT_EOK;
nu_i2s_t psNuSPII2s;
nu_acodec_ops_t pNuACodecOps = RT_NULL;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
nu_acodec_ops_t pNuACodecOps;
RT_ASSERT(audio != RT_NULL);
RT_ASSERT(caps != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
pNuACodecOps = psNuSPII2s->AcodecOps;
@ -367,6 +365,10 @@ static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio
} // switch (caps->sub_type)
break;
default:
result = -RT_ERROR;
break;
} // switch (caps->main_type)
return result;
@ -375,16 +377,14 @@ static rt_err_t nu_spii2s_getcaps(struct rt_audio_device *audio, struct rt_audio
static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
rt_err_t result = RT_EOK;
nu_i2s_t psNuSPII2s;
nu_acodec_ops_t pNuACodecOps = RT_NULL;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
nu_acodec_ops_t pNuACodecOps;
int stream = -1;
RT_ASSERT(audio != RT_NULL);
RT_ASSERT(caps != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
RT_ASSERT(psNuSPII2s->AcodecOps != RT_NULL);
pNuACodecOps = psNuSPII2s->AcodecOps;
switch (caps->main_type)
@ -394,7 +394,6 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
psNuSPII2s->AcodecOps->nu_acodec_mixer_control(caps->sub_type, caps->udata.value);
break;
case AUDIO_TYPE_INPUT:
stream = AUDIO_STREAM_RECORD;
case AUDIO_TYPE_OUTPUT:
@ -445,6 +444,7 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
}
}
break;
default:
result = -RT_ERROR;
break;
@ -456,12 +456,10 @@ static rt_err_t nu_spii2s_configure(struct rt_audio_device *audio, struct rt_aud
static rt_err_t nu_spii2s_init(struct rt_audio_device *audio)
{
rt_err_t result = RT_EOK;
nu_i2s_t psNuSPII2s;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
RT_ASSERT(audio != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
/* Reset this module */
SYS_ResetModule(psNuSPII2s->i2s_rst);
@ -470,13 +468,12 @@ static rt_err_t nu_spii2s_init(struct rt_audio_device *audio)
static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
{
nu_i2s_t psNuSPII2s;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
SPI_T *spii2s_base;
RT_ASSERT(audio != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
/* Restart all: SPII2S and codec. */
nu_spii2s_stop(audio, stream);
@ -512,6 +509,8 @@ static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
LOG_I("Start record.");
}
break;
default:
return -RT_ERROR;
}
return RT_EOK;
@ -519,14 +518,13 @@ static rt_err_t nu_spii2s_start(struct rt_audio_device *audio, int stream)
static rt_err_t nu_spii2s_stop(struct rt_audio_device *audio, int stream)
{
nu_i2s_t psNuSPII2s;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
nu_i2s_dai_t psNuSPII2sDai = RT_NULL;
SPI_T *spii2s_base;
RT_ASSERT(audio != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
SPI_T *spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
spii2s_base = (SPI_T *)psNuSPII2s->i2s_base;
switch (stream)
{
@ -574,13 +572,11 @@ static rt_err_t nu_spii2s_stop(struct rt_audio_device *audio, int stream)
static void nu_spii2s_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
{
nu_i2s_t psNuSPII2s;
nu_i2s_t psNuSPII2s = (nu_i2s_t)audio;
RT_ASSERT(audio != RT_NULL);
RT_ASSERT(info != RT_NULL);
psNuSPII2s = (nu_i2s_t)audio;
info->buffer = (rt_uint8_t *)psNuSPII2s->i2s_dais[NU_I2S_DAI_PLAYBACK].fifo ;
info->total_size = NU_I2S_DMA_FIFO_SIZE;
info->block_size = NU_I2S_DMA_BUF_BLOCK_SIZE;
@ -618,12 +614,12 @@ nu_hw_spii2s_pdma_allocate:
int rt_hw_spii2s_init(void)
{
int i = 0, j = 0;
int j = 0;
nu_i2s_dai_t psNuSPII2sDai;
for (j = (SPII2S_START + 1); j < SPII2S_CNT; j++)
{
int i = 0;
for (i = 0; i < NU_I2S_DAI_CNT; i++)
{
uint8_t *pu8ptr = rt_malloc(NU_I2S_DMA_FIFO_SIZE);

View File

@ -72,7 +72,7 @@ void timer_interrupt_handler(nu_capture_t *nu_timer_capture)
{
TIMER_ClearCaptureIntFlag(nu_timer_capture->timer);
/* Frist event is rising edge */
/* First event is rising edge */
if (nu_timer_capture->first_edge == RT_TRUE)
{
nu_timer_capture->first_edge = RT_FALSE;

View File

@ -27,8 +27,10 @@ static int s_i32TRNGEnable = 0;
static rt_uint32_t nu_trng_run(void)
{
uint32_t u32RNGValue;
rt_err_t result;
rt_mutex_take(&s_TRNG_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_TRNG_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
TRNG_Open();
@ -38,13 +40,18 @@ static rt_uint32_t nu_trng_run(void)
u32RNGValue = rand();
}
rt_mutex_release(&s_TRNG_mutex);
result = rt_mutex_release(&s_TRNG_mutex);
RT_ASSERT(result == RT_EOK);
return u32RNGValue;
}
rt_err_t nu_trng_init(void)
{
rt_mutex_init(&s_TRNG_mutex, NU_CRYPTO_TRNG_NAME, RT_IPC_FLAG_FIFO);
rt_err_t result;
result = rt_mutex_init(&s_TRNG_mutex, NU_CRYPTO_TRNG_NAME, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
if ((SYS->CSERVER & SYS_CSERVER_VERSION_Msk) == 0x0)
{

View File

@ -22,6 +22,7 @@
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#include <rtdbg.h>
#define SLV_10BIT_ADDR (0x1E<<2) //1111+0xx+r/w
@ -382,4 +383,4 @@ int rt_hw_ui2c_init(void)
INIT_DEVICE_EXPORT(rt_hw_ui2c_init);
#endif //#if (defined(BSP_USING_UI2C) && defined(RT_USING_I2C))
#endif //#if defined(BSP_USING_UI2C)

View File

@ -288,7 +288,7 @@ __STATIC_INLINE void _USBD_IRQHandler(void)
}
else
{
/* USB Un-plug */
/* USB Unplug */
USBD_DISABLE_USB();
rt_usbd_disconnect_handler(&_rt_obj_udc);
}
@ -447,7 +447,6 @@ void USBD_IRQHandler(void)
_USBD_IRQHandler();
/* leave interrupt */
rt_interrupt_leave();
}
@ -523,7 +522,7 @@ int nu_usbd_register(void)
_rt_obj_udc.parent.user_data = &nu_usbd;
_rt_obj_udc.ops = &_udc_ops;
/* Register endpoint infomation */
/* Register endpoint information */
_rt_obj_udc.ep_pool = _ep_pool;
_rt_obj_udc.ep0.id = &_ep_pool[0];

View File

@ -446,7 +446,6 @@ static void int_xfer_done_cb(UTR_T *psUTR)
free_utr(psUTR);
}
static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
S_NU_RH_PORT_CTRL *psPortCtrl;
@ -505,7 +504,6 @@ static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes
}
}
//others xfer
rt_completion_init(&(psPortDev->utr_completion));
@ -694,7 +692,6 @@ static void nu_hcd_disconnect_callback(
rt_usbh_root_hub_disconnect_handler(s_sUSBHDev.uhcd, port_index);
}
/* USB host operations -----------------------------------------------------------*/
static struct uhcd_ops nu_uhcd_ops =
{
@ -706,7 +703,7 @@ static struct uhcd_ops nu_uhcd_ops =
static rt_err_t nu_hcd_init(rt_device_t device)
{
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
usbh_core_init();
//install connect/disconnect callback
@ -716,11 +713,11 @@ static rt_err_t nu_hcd_init(rt_device_t device)
//create thread for polling usbh port status
/* create usb hub thread */
pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL,
NU_USBH_THREAD_STACK_SIZE, 8, 20);
if ( pNuUSBHDev->polling_thread != RT_NULL)
NU_USBH_THREAD_STACK_SIZE, 8, 20);
if (pNuUSBHDev->polling_thread != RT_NULL)
{
/* startup usb host thread */
rt_thread_startup( pNuUSBHDev->polling_thread );
rt_thread_startup(pNuUSBHDev->polling_thread);
}
else
{
@ -751,15 +748,20 @@ uint32_t usbh_tick_from_millisecond(uint32_t msec)
/* device pm suspend() entry. */
static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
{
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
rt_err_t result;
RT_ASSERT(pNuUSBHDev!=RT_NULL);
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
RT_ASSERT(pNuUSBHDev != RT_NULL);
switch (mode)
{
case PM_SLEEP_MODE_LIGHT:
case PM_SLEEP_MODE_DEEP:
pNuUSBHDev->polling_thread->stat = RT_THREAD_READY;
rt_thread_suspend(pNuUSBHDev->polling_thread);
result = rt_thread_suspend(pNuUSBHDev->polling_thread);
RT_ASSERT(result == RT_EOK);
break;
default:
@ -772,14 +774,16 @@ static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
/* device pm resume() entry. */
static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode)
{
struct nu_usbh_dev * pNuUSBHDev = (struct nu_usbh_dev *)device;
RT_ASSERT(pNuUSBHDev!=RT_NULL);
rt_err_t result;
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
RT_ASSERT(pNuUSBHDev != RT_NULL);
switch (mode)
{
case PM_SLEEP_MODE_LIGHT:
case PM_SLEEP_MODE_DEEP:
rt_thread_resume(pNuUSBHDev->polling_thread);
result = rt_thread_resume(pNuUSBHDev->polling_thread);
RT_ASSERT(result == RT_EOK);
break;
default:
@ -846,7 +850,7 @@ int nu_usbh_register(void)
#if defined(RT_USING_PM)
rt_pm_device_register(&uhcd->parent, &device_pm_ops);
#endif
return RT_EOK;
}
INIT_DEVICE_EXPORT(nu_usbh_register);

View File

@ -12,6 +12,14 @@
#include <rtconfig.h>
#if defined(BSP_USING_USPI)
#define LOG_TAG "drv.uspi"
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#include <rtdbg.h>
#include <rthw.h>
#include <rtdevice.h>
#include <rtdef.h>
@ -56,7 +64,8 @@ typedef struct nu_uspi *uspi_t;
/* Private functions ------------------------------------------------------------*/
static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus, uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word);
static int nu_uspi_register_bus(struct nu_uspi *uspi_bus, const char *name);
static void nu_uspi_drain_rxfifo(USPI_T *uspi_base);
@ -160,7 +169,7 @@ static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
u32BusClock = USPI_SetBusClock(uspi_bus->uspi_base, configuration->max_hz);
if (configuration->max_hz > u32BusClock)
{
rt_kprintf("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
LOG_W("%s clock max frequency is %dHz (!= %dHz)\n", uspi_bus->name, u32BusClock, configuration->max_hz);
configuration->max_hz = u32BusClock;
}
@ -194,7 +203,7 @@ static rt_err_t nu_uspi_bus_configure(struct rt_spi_device *device,
}
}
/* Clear SPI RX FIFO */
/* Clear USPI RX FIFO */
nu_uspi_drain_rxfifo(uspi_bus->uspi_base);
exit_nu_uspi_bus_configure:
@ -205,16 +214,18 @@ exit_nu_uspi_bus_configure:
#if defined(BSP_USING_USPI_PDMA)
static void nu_pdma_uspi_rx_cb(void *pvUserData, uint32_t u32EventFilter)
{
struct nu_uspi *uspi_bus;
uspi_bus = (struct nu_uspi *)pvUserData;
rt_err_t result;
struct nu_uspi *uspi_bus = (struct nu_uspi *)pvUserData;
RT_ASSERT(uspi_bus != RT_NULL);
rt_sem_release(uspi_bus->m_psSemBus);
result = rt_sem_release(uspi_bus->m_psSemBus);
RT_ASSERT(result == RT_EOK);
}
static rt_err_t nu_pdma_uspi_rx_config(struct nu_uspi *uspi_bus, uint8_t *pu8Buf, int32_t i32RcvLen, uint8_t bytes_per_word)
{
rt_err_t result = RT_ERROR;
rt_err_t result;
rt_uint8_t *dst_addr = NULL;
nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
@ -263,7 +274,7 @@ exit_nu_pdma_uspi_rx_config:
static rt_err_t nu_pdma_uspi_tx_config(struct nu_uspi *uspi_bus, const uint8_t *pu8Buf, int32_t i32SndLen, uint8_t bytes_per_word)
{
rt_err_t result = RT_ERROR;
rt_err_t result;
rt_uint8_t *src_addr = NULL;
nu_pdma_memctrl_t memctrl = eMemCtl_Undefined;
@ -304,11 +315,11 @@ exit_nu_pdma_uspi_tx_config:
/**
* SPI PDMA transfer
*/
* USPI PDMA transfer
**/
static rt_size_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *send_addr, uint8_t *recv_addr, int length, uint8_t bytes_per_word)
{
rt_err_t result = RT_ERROR;
rt_err_t result;
/* Get base address of uspi register */
USPI_T *uspi_base = uspi_bus->uspi_base;
@ -322,7 +333,8 @@ static rt_size_t nu_uspi_pdma_transmit(struct nu_uspi *uspi_bus, const uint8_t *
USPI_TRIGGER_TX_RX_PDMA(uspi_base);
/* Wait PDMA transfer done */
rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
result = rt_sem_take(uspi_bus->m_psSemBus, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Stop DMA TX/RX transfer */
USPI_DISABLE_TX_RX_PDMA(uspi_base);
@ -345,6 +357,7 @@ static rt_err_t nu_hw_uspi_pdma_allocate(struct nu_uspi *uspi_bus)
}
uspi_bus->m_psSemBus = rt_sem_create("uspibus_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(uspi_bus->m_psSemBus != RT_NULL);
return RT_EOK;
@ -373,10 +386,10 @@ static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per
// Read RX data
if (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
{
uint32_t val;
// Read data from USPI RX FIFO
switch (bytes_per_word)
{
uint32_t val;
case 2:
val = USPI_READ_RX(uspi_base);
nu_set16_le(recv_addr, val);
@ -385,6 +398,7 @@ static int nu_uspi_read(USPI_T *uspi_base, uint8_t *recv_addr, uint8_t bytes_per
*recv_addr = USPI_READ_RX(uspi_base);
break;
default:
LOG_E("Data length is not supported.\n");
break;
}
size = bytes_per_word;
@ -397,7 +411,7 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
// Wait USPI TX send data
while (USPI_GET_TX_FULL_FLAG(uspi_base));
// Input data to SPI TX
// Input data to USPI TX
switch (bytes_per_word)
{
case 2:
@ -407,6 +421,7 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
USPI_WRITE_TX(uspi_base, *((uint8_t *)send_addr));
break;
default:
LOG_E("Data length is not supported.\n");
break;
}
@ -414,8 +429,8 @@ static int nu_uspi_write(USPI_T *uspi_base, const uint8_t *send_addr, uint8_t by
}
/**
* @brief SPI bus polling
* @param dev : The pointer of the specified SPI module.
* @brief USPI bus polling
* @param dev : The pointer of the specified USPI module.
* @param send_addr : Source address
* @param recv_addr : Destination address
* @param length : Data length
@ -440,10 +455,10 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
uspi_bus->dummy = 0;
while (length > 0)
{
/* Input data to SPI TX FIFO */
/* Input data to USPI TX FIFO */
length -= nu_uspi_write(uspi_base, (const uint8_t *)&uspi_bus->dummy, bytes_per_word);
/* Read data from RX FIFO */
/* Read data from USPI RX FIFO */
while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
}
@ -453,20 +468,20 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
{
while (length > 0)
{
/* Input data to SPI TX FIFO */
/* Input data to USPI TX FIFO */
send_addr += nu_uspi_write(uspi_base, send_addr, bytes_per_word);
length -= bytes_per_word;
/* Read data from RX FIFO */
/* Read data from USPI RX FIFO */
while (USPI_GET_RX_EMPTY_FLAG(uspi_base));
recv_addr += nu_uspi_read(uspi_base, recv_addr, bytes_per_word);
}
} // else
/* Wait RX or drain RX-FIFO */
/* Wait USPI RX or drain USPI RX-FIFO */
if (recv_addr)
{
// Wait SPI transmission done
// Wait USPI transmission done
while (USPI_IS_BUSY(uspi_base))
{
while (!USPI_GET_RX_EMPTY_FLAG(uspi_base))
@ -482,7 +497,7 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
}
else
{
/* Clear SPI RX FIFO */
/* Clear USPI RX FIFO */
nu_uspi_drain_rxfifo(uspi_base);
}
}
@ -490,10 +505,10 @@ static void nu_uspi_transmission_with_poll(struct nu_uspi *uspi_bus,
static void nu_uspi_transfer(struct nu_uspi *uspi_bus, uint8_t *tx, uint8_t *rx, int length, uint8_t bytes_per_word)
{
#if defined(BSP_USING_USPI_PDMA)
/* DMA transfer constrains */
/* PDMA transfer constrains */
if ((uspi_bus->pdma_chanid_rx >= 0) &&
!((uint32_t)tx % bytes_per_word) &&
!((uint32_t)rx % bytes_per_word))
(!((uint32_t)tx % bytes_per_word)) &&
(!((uint32_t)rx % bytes_per_word)))
nu_uspi_pdma_transmit(uspi_bus, tx, rx, length, bytes_per_word);
else
nu_uspi_transmission_with_poll(uspi_bus, tx, rx, length, bytes_per_word);
@ -519,7 +534,7 @@ static rt_uint32_t nu_uspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
if ((message->length % bytes_per_word) != 0)
{
/* Say bye. */
rt_kprintf("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
LOG_E("%s: error payload length(%d%%%d != 0).\n", uspi_bus->name, message->length, bytes_per_word);
return 0;
}
@ -578,7 +593,7 @@ static int rt_hw_uspi_init(void)
{
if (nu_hw_uspi_pdma_allocate(&nu_uspi_arr[i]) != RT_EOK)
{
rt_kprintf("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
LOG_E("Failed to allocate DMA channels for %s. We will use poll-mode for this bus.\n", nu_uspi_arr[i].name);
}
}
#endif

View File

@ -484,7 +484,7 @@ static int nu_hw_uuart_dma_allocate(nu_uuart_t puuart)
static rt_err_t nu_uuart_control(struct rt_serial_device *serial, int cmd, void *arg)
{
rt_err_t result = RT_EOK;
rt_uint32_t flag;
rt_uint32_t flag = 0;
rt_ubase_t ctrl_arg = (rt_ubase_t)arg;
RT_ASSERT(serial != RT_NULL);

View File

@ -23,10 +23,10 @@
- For record function: Run it w/o parameter.
- For replay function: Run it with parameter.
*/
static void audio_test(int argc, char **argv)
static int audio_test(int argc, char **argv)
{
#define DEF_MAX_ARGV_NUM 8
int smplrate[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
int smplrate[] = {8000, 16000, 44100, 48000};
int smplbit[] = {16};
int chnum[] = {1, 2};
struct wavrecord_info info;
@ -74,6 +74,8 @@ static void audio_test(int argc, char **argv)
} // k
} // j
} // i
return 0;
}
#ifdef FINSH_USING_MSH

View File

@ -1,3 +1,15 @@
/**************************************************************************//**
*
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-1-10 Wayne First version
*
******************************************************************************/
#include <rtthread.h>
#if defined(RT_USB_DEVICE_CDC) && (defined(BSP_USING_USBD) || defined(BSP_USING_HSUSBD))
@ -6,7 +18,11 @@ static struct rt_semaphore rx_sem;
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
rt_sem_release(&rx_sem);
rt_err_t result = 0;
result = rt_sem_release(&rx_sem);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
@ -21,10 +37,8 @@ static void serial_thread_entry(void *parameter)
{
if (rt_sem_take(&rx_sem, 3 * RT_TICK_PER_SECOND) == -RT_ETIMEOUT)
{
time_t now;
/* output current time */
now = time(RT_NULL);
rt_snprintf(szStr, sizeof(szStr), "%.*s\n", 25, ctime(&now));
/* output current tick */
rt_snprintf(szStr, sizeof(szStr), "%d\n", rt_tick_get());
rt_device_write(serial, 0, &szStr[0], rt_strlen(szStr));
continue;
}
@ -35,7 +49,7 @@ static void serial_thread_entry(void *parameter)
static int vcom_echo_init(void)
{
int err = 0;
rt_err_t result = 0;
rt_thread_t thread;
rt_device_t serial;
@ -45,25 +59,33 @@ static int vcom_echo_init(void)
rt_kprintf("find failed!\n");
return RT_ERROR;
}
err = rt_device_init(serial);
if (err)
result = rt_device_init(serial);
if (result)
{
rt_kprintf("find failed!\n");
return -RT_ERROR;
rt_kprintf("init failed!\n");
return -1;
}
result = rt_device_open(serial, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX/* | RT_DEVICE_FLAG_DMA_TX */);
if (result)
{
rt_kprintf("open failed!\n");
return -1;
}
err = rt_device_open(serial, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX/* | RT_DEVICE_FLAG_DMA_TX */);
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
result = rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
rt_device_set_rx_indicate(serial, uart_input);
result = rt_device_set_rx_indicate(serial, uart_input);
RT_ASSERT(result == RT_EOK);
thread = rt_thread_create("serial", serial_thread_entry, (void *)serial, 1024, 25, 10);
if (thread != RT_NULL)
{
rt_thread_startup(thread);
result = rt_thread_startup(thread);
RT_ASSERT(result == RT_EOK);
}
return RT_EOK;
return 0;
}
INIT_APP_EXPORT(vcom_echo_init);

View File

@ -35,15 +35,17 @@ static void usb_thread_entry(void *parameter)
{
int8_t i8MouseTable[] = { -16, -16, -16, 0, 16, 16, 16, 0};
uint8_t u8MouseIdx = 0;
uint8_t u8MoveLen=0, u8MouseMode = 1;
uint8_t u8MoveLen = 0, u8MouseMode = 1;
uint8_t pu8Buf[4];
rt_err_t result = RT_EOK;
rt_device_t device = (rt_device_t)parameter;
rt_sem_init(&tx_sem_complete, "tx_complete_sem_hid", 1, RT_IPC_FLAG_FIFO);
result = rt_sem_init(&tx_sem_complete, "tx_complete_sem_hid", 1, RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
rt_device_set_tx_complete(device, event_hid_in);
result = rt_device_set_tx_complete(device, event_hid_in);
RT_ASSERT(result == RT_EOK);
LOG_I("Ready.\n");
@ -79,7 +81,7 @@ static void usb_thread_entry(void *parameter)
{
/* Wait it done. */
result = rt_sem_take(&tx_sem_complete, RT_WAITING_FOREVER);
RT_ASSERT( result== RT_EOK );
RT_ASSERT(result == RT_EOK);
}
} // while(1)
@ -96,10 +98,10 @@ static int dance_mouse_init(void)
RT_ASSERT(ret == RT_EOK);
ret = rt_thread_init(&usb_thread,
"hidd",
usb_thread_entry, device,
usb_thread_stack, sizeof(usb_thread_stack),
10, 20);
"hidd",
usb_thread_entry, device,
usb_thread_stack, sizeof(usb_thread_stack),
10, 20);
RT_ASSERT(ret == RT_EOK);
ret = rt_thread_startup(&usb_thread);

View File

@ -62,4 +62,10 @@ menu "Nuvoton Packages Config"
endif
config NU_PKG_USING_SPINAND
bool "SPI NAND flash."
select BSP_USING_QSPI
select RT_USING_MTD_NAND
default n
endmenu

View File

@ -0,0 +1,12 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
group = []
if GetDepend('NU_PKG_USING_SPINAND'):
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
group = DefineGroup('nu_pkgs_spinand', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,912 @@
/**************************************************************************//**
*
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-1-13 Wayne First version
*
******************************************************************************/
#include <rtthread.h>
#if defined(NU_PKG_USING_SPINAND) && defined(RT_USING_MTD_NAND)
#define LOG_TAG "drv_spinand"
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#include <rtdbg.h>
#include "spinand.h"
struct nu_spinand g_spinandflash_dev = {0};
rt_size_t nu_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message)
{
rt_err_t result;
struct rt_spi_message *index;
RT_ASSERT(device != RT_NULL);
RT_ASSERT(message != RT_NULL);
result = rt_mutex_take(&(device->parent.bus->lock), RT_WAITING_FOREVER);
if (result != RT_EOK)
{
rt_set_errno(-RT_EBUSY);
return 0;
}
/* reset errno */
rt_set_errno(RT_EOK);
/* configure SPI bus */
if (device->parent.bus->owner != &device->parent)
{
/* not the same owner as current, re-configure SPI bus */
result = device->parent.bus->ops->configure(&device->parent, &device->parent.config);
if (result == RT_EOK)
{
/* set SPI bus owner */
device->parent.bus->owner = &device->parent;
}
else
{
/* configure SPI bus failed */
rt_set_errno(-RT_EIO);
goto __exit;
}
}
/* transmit each SPI message */
index = &message->parent;
while (index)
{
if (device->parent.bus->ops->xfer(&device->parent, index) == 0)
{
result = -RT_EIO;
rt_set_errno(-RT_EIO);
goto __exit;
}
index = index->next;
}
result = RT_EOK;
__exit:
/* release bus lock */
rt_mutex_release(&(device->parent.bus->lock));
return result;
}
rt_err_t nu_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length)
{
struct rt_qspi_message message[2] = {0};
RT_ASSERT(send_buf);
RT_ASSERT(recv_buf);
RT_ASSERT(send_length != 0);
/* Send message */
message[0].qspi_data_lines = 1;
/* Set send buf and send size */
message[0].parent.recv_buf = RT_NULL;
message[0].parent.send_buf = send_buf;
message[0].parent.length = send_length;
message[0].parent.cs_take = 1;
message[0].parent.next = &message[1].parent;
/* Receive message */
message[1].qspi_data_lines = 1;
/* Set recv buf and recv size */
message[1].parent.recv_buf = recv_buf;
message[1].parent.send_buf = RT_NULL;
message[1].parent.length = recv_length;
message[1].parent.cs_release = 1;
return nu_qspi_transfer_message(device, &message[0]);
}
rt_err_t nu_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length)
{
RT_ASSERT(send_buf);
RT_ASSERT(length != 0);
struct rt_qspi_message message = {0};
char *ptr = (char *)send_buf;
rt_size_t count = 0;
message.instruction.content = ptr[0];
message.instruction.qspi_lines = 1;
count++;
/* set send buf and send size */
message.qspi_data_lines = 1;
message.parent.send_buf = ptr + count;
message.parent.recv_buf = RT_NULL;
message.parent.length = length - count;
message.parent.cs_take = 1;
message.parent.cs_release = 1;
return nu_qspi_transfer_message(device, &message);
}
static void spinand_dump_buffer(int page, rt_uint8_t *buf, int len, const char *title)
{
if ((DBG_LEVEL) >= DBG_LOG)
{
int i;
if (!buf)
{
return;
}
/* Just print 64-bytes.*/
len = (len < 64) ? len : 64;
LOG_I("[%s-Page-%d]", title, page);
for (i = 0; i < len; i ++)
{
rt_kprintf("%02X ", buf[i]);
if (i % 32 == 31) rt_kprintf("\n");
}
rt_kprintf("\n");
}
}
static rt_err_t spinand_read_id(struct rt_mtd_nand_device *device)
{
rt_err_t result = RT_EOK ;
uint32_t id = 0;
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
SPINAND_FLASH_OPS->jedecid_get(SPINAND_FLASH_QSPI, &id);
result = rt_mutex_release(SPINAND_FLASH_LOCK);
RT_ASSERT(result == RT_EOK);
return (id != 0x0) ? RT_EOK : -RT_ERROR;
}
static rt_err_t spinand_read_page(struct rt_mtd_nand_device *device,
rt_off_t page,
rt_uint8_t *data,
rt_uint32_t data_len,
rt_uint8_t *spare,
rt_uint32_t spare_len)
{
rt_err_t result = RT_EOK ;
LOG_D("[R-%d]data: 0x%08x %d, spare: 0x%08x, %d", page, data, data_len, spare, spare_len);
RT_ASSERT(device != RT_NULL);
if (page / device->pages_per_block > device->block_end)
{
LOG_E("[EIO] read page:%d", page);
return -RT_MTD_EIO;
}
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Data load, Read data from flash to cache */
result = SPINAND_FLASH_OPS->read_dataload(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, (page & 0xFF));
if (result != RT_EOK)
goto exit_spinand_read_page;
if (data && data_len)
{
/* Read data: 0~data_len, Read cache to data */
result = SPINAND_FLASH_OPS->read_quadoutput(SPINAND_FLASH_QSPI, 0, 0, data, data_len);
if (result != RT_EOK)
goto exit_spinand_read_page;
}
if (spare && spare_len)
{
/* Read data: 2048~spare_len, Read cache to spare */
result = SPINAND_FLASH_OPS->read_quadoutput(SPINAND_FLASH_QSPI, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, spare, spare_len);
if (result != RT_EOK)
goto exit_spinand_read_page;
}
exit_spinand_read_page:
rt_mutex_release(SPINAND_FLASH_LOCK);
spinand_dump_buffer(page, data, data_len, "Read Data");
spinand_dump_buffer(page, spare, spare_len, "Read Spare");
return result;
}
static rt_err_t spinand_write_page(struct rt_mtd_nand_device *device,
rt_off_t page,
const rt_uint8_t *data,
rt_uint32_t data_len,
const rt_uint8_t *spare,
rt_uint32_t spare_len)
{
rt_err_t result = RT_EOK ;
LOG_D("[W-%d]data: 0x%08x %d, spare: 0x%08x, %d", page, data, data_len, spare, spare_len);
RT_ASSERT(device != RT_NULL);
if (page / device->pages_per_block > device->block_end)
{
LOG_E("[EIO] write page:%d", page);
return -RT_MTD_EIO;
}
spinand_dump_buffer(page, (uint8_t *)data, data_len, "WRITE DATA");
spinand_dump_buffer(page, (uint8_t *)spare, spare_len, "WRITE SPARE");
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
if (SPINAND_FLASH_MCP == 1)
{
/* Select die. */
if ((result = SPINAND_FLASH_OPS->die_select(SPINAND_FLASH_QSPI, SPINAND_DIE_ID0)) != RT_EOK)
goto exit_spinand_write_page;
}
/* Read data: 0~2111, to cache */
if (data && data_len)
result = SPINAND_FLASH_OPS->program_dataload(SPINAND_FLASH_QSPI, 0, 0, (uint8_t *)data, data_len, (uint8_t *)spare, spare_len);
else
result = SPINAND_FLASH_OPS->program_dataload(SPINAND_FLASH_QSPI, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, RT_NULL, 0, (uint8_t *)spare, spare_len);
if (result != RT_EOK)
goto exit_spinand_write_page;
/* Flush data in cache to flash */
result = SPINAND_FLASH_OPS->program_execute(SPINAND_FLASH_QSPI, (((page) >> 16) & 0xFF), (((page) >> 8) & 0xFF), (page) & 0xFF);
if (result != RT_EOK)
goto exit_spinand_write_page;
result = RT_EOK;
exit_spinand_write_page:
rt_mutex_release(SPINAND_FLASH_LOCK);
return result;
}
static rt_err_t spinand_move_page(struct rt_mtd_nand_device *device, rt_off_t src_page, rt_off_t dst_page)
{
rt_err_t result = RT_EOK ;
uint8_t u8WECmd;
RT_ASSERT(device != RT_NULL);
if ((src_page / device->pages_per_block > device->block_end) ||
(dst_page / device->pages_per_block > device->block_end))
{
LOG_E("EIO src:%08x, dst:%08x!", src_page, dst_page);
return -RT_MTD_EIO;
}
LOG_D("src_page: %d, dst_page: %d", src_page, dst_page);
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Data load, Read data from flash to cache */
result = SPINAND_FLASH_OPS->read_dataload(SPINAND_FLASH_QSPI, (src_page >> 16) & 0xFF, (src_page >> 8) & 0xFF, (src_page & 0xFF));
if (result != RT_EOK)
goto exit_spinand_move_page;
/* Enable WE before writting. */
u8WECmd = 0x06;
if ((result = nu_qspi_send(SPINAND_FLASH_QSPI, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
goto exit_spinand_move_page;
/* Flush cache to flash */
result = SPINAND_FLASH_OPS->program_execute(SPINAND_FLASH_QSPI, (((dst_page) >> 16) & 0xFF), (((dst_page) >> 8) & 0xFF), (dst_page) & 0xFF);
if (result != RT_EOK)
goto exit_spinand_move_page;
result = RT_EOK;
exit_spinand_move_page:
rt_mutex_release(SPINAND_FLASH_LOCK);
return result;
}
static rt_err_t spinand_erase_block_force(struct rt_mtd_nand_device *device, rt_uint32_t block)
{
rt_err_t result = RT_EOK ;
uint32_t page;
RT_ASSERT(device != RT_NULL);
if (block > device->block_end)
{
LOG_E("[EIO] block:%d", block);
return -RT_MTD_EIO;
}
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
LOG_D("force erase block: %d -> page: %d", block, page);
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
result = SPINAND_FLASH_OPS->block_erase(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, page & 0xFF);
if (result != RT_EOK)
goto exit_spinand_erase_block_force;
result = RT_EOK;
exit_spinand_erase_block_force:
rt_mutex_release(SPINAND_FLASH_LOCK);
return result;
}
static rt_err_t spinand_erase_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
{
rt_err_t result = RT_EOK ;
uint32_t page;
RT_ASSERT(device != RT_NULL);
if (block > device->block_end)
{
LOG_E("[EIO] block:%d", block);
return -RT_MTD_EIO;
}
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
LOG_D("erase block: %d -> page: %d", block, page);
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Erase block after checking it is bad or not. */
if (SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page) != 0)
{
LOG_W("Block %d is bad.\n", block);
result = -RT_ERROR;
goto exit_spinand_erase_block;
}
else
{
result = SPINAND_FLASH_OPS->block_erase(SPINAND_FLASH_QSPI, (page >> 16) & 0xFF, (page >> 8) & 0xFF, page & 0xFF);
if (result != RT_EOK)
goto exit_spinand_erase_block;
}
result = RT_EOK;
exit_spinand_erase_block:
rt_mutex_release(SPINAND_FLASH_LOCK);
return result;
}
static rt_err_t spinand_check_block(struct rt_mtd_nand_device *device, rt_uint32_t block)
{
rt_err_t result = RT_EOK ;
uint32_t page = 0;
uint8_t isbad = 0;
RT_ASSERT(device != RT_NULL);
if (block > device->block_end)
{
LOG_E("[EIO] block:%d", block);
return -RT_MTD_EIO;
}
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
LOG_D("check block status: %d -> page: %d", block, page);
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
isbad = SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page);
result = rt_mutex_release(SPINAND_FLASH_LOCK);
RT_ASSERT(result == RT_EOK);
return (isbad == 0) ? RT_EOK : -RT_ERROR ;
}
static rt_err_t spinand_mark_badblock(struct rt_mtd_nand_device *device, rt_uint32_t block)
{
rt_err_t result = RT_EOK ;
uint32_t page = 0;
RT_ASSERT(device != RT_NULL);
if (block > device->block_end)
{
LOG_E("[EIO] block:%d", block);
return -RT_MTD_EIO;
}
page = block * SPINAND_FLASH_PAGE_PER_BLOCK_NUM;
LOG_D("mark bad block: %d -> page: %d", block, page);
result = rt_mutex_take(SPINAND_FLASH_LOCK, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Erase block after checking it is bad or not. */
if (SPINAND_FLASH_OPS->block_isbad(SPINAND_FLASH_QSPI, page) != 0)
{
LOG_W("Block %d is bad.\n", block);
result = RT_EOK;
}
else
{
result = SPINAND_FLASH_OPS->block_markbad(SPINAND_FLASH_QSPI, page);
}
rt_mutex_release(SPINAND_FLASH_LOCK);
return result;
}
static struct rt_mtd_nand_driver_ops spinand_ops =
{
spinand_read_id,
spinand_read_page,
spinand_write_page,
spinand_move_page,
spinand_erase_block,
spinand_check_block,
spinand_mark_badblock
};
static uint32_t u32IsInited = 0;
rt_err_t rt_hw_mtd_spinand_init(void)
{
int i = 0;
rt_err_t result;
char szTmp[8];
if (u32IsInited)
return RT_EOK;
result = rt_mutex_init(SPINAND_FLASH_LOCK, "spinand", RT_IPC_FLAG_FIFO);
RT_ASSERT(result == RT_EOK);
result = spinand_flash_init(SPINAND_FLASH_QSPI);
RT_ASSERT(result == RT_EOK);
for (i = 0; i < MTD_SPINAND_PARTITION_NUM; i++)
{
mtd_partitions[i].page_size = SPINAND_FLASH_PAGE_SIZE; /* The Page size in the flash */
mtd_partitions[i].pages_per_block = SPINAND_FLASH_PAGE_PER_BLOCK_NUM; /* How many page number in a block */
mtd_partitions[i].oob_size = SPINAND_FLASH_OOB_SIZE; /* Out of bank size */
mtd_partitions[i].oob_free = 32; /* the free area in oob that flash driver not use */
mtd_partitions[i].plane_num = SPINAND_FLASH_MCP ; /* the number of plane in the NAND Flash */
mtd_partitions[i].ops = &spinand_ops;
rt_snprintf(szTmp, sizeof(szTmp), "nand%d", i);
result = rt_mtd_nand_register_device(szTmp, &mtd_partitions[i]);
RT_ASSERT(result == RT_EOK);
}
u32IsInited = 1;
return result;
}
rt_err_t rt_hw_mtd_spinand_register(const char *device_name)
{
rt_device_t pDev;
rt_err_t result;
if ((pDev = rt_device_find(device_name)) == RT_NULL)
return -RT_ERROR;
SPINAND_FLASH_QSPI = (struct rt_qspi_device *)pDev;
SPINAND_FLASH_QSPI->config.parent.mode = RT_SPI_MODE_0 | RT_SPI_MSB;
SPINAND_FLASH_QSPI->config.parent.data_width = 8;
SPINAND_FLASH_QSPI->config.parent.max_hz = 48000000;
SPINAND_FLASH_QSPI->config.ddr_mode = 0;
SPINAND_FLASH_QSPI->config.qspi_dl_width = 4;
result = rt_spi_configure(&SPINAND_FLASH_QSPI->parent, &SPINAND_FLASH_QSPI->config.parent);
RT_ASSERT(result == RT_EOK);
return rt_hw_mtd_spinand_init();
}
#if defined(RT_USING_DFS_UFFS)
#include "dfs_uffs.h"
void uffs_setup_storage(struct uffs_StorageAttrSt *attr,
struct rt_mtd_nand_device *nand)
{
RT_ASSERT(attr != RT_NULL);
RT_ASSERT(nand != RT_NULL);
rt_memset(attr, 0, sizeof(struct uffs_StorageAttrSt));
attr->page_data_size = nand->page_size; /* page data size */
attr->pages_per_block = nand->pages_per_block; /* pages per block */
attr->spare_size = nand->oob_size; /* page spare size */
attr->ecc_opt = RT_CONFIG_UFFS_ECC_MODE; /* ecc option */
attr->ecc_size = nand->oob_size - nand->oob_free; /* ecc size */
attr->block_status_offs = 0; /* indicate block bad or good, offset in spare */
attr->layout_opt = RT_CONFIG_UFFS_LAYOUT; /* let UFFS do the spare layout */
/* initialize _uffs_data_layout and _uffs_ecc_layout */
rt_memcpy(attr->_uffs_data_layout, spinand_flash_data_layout, UFFS_SPARE_LAYOUT_SIZE);
rt_memcpy(attr->_uffs_ecc_layout, spinand_flash_ecc_layout, UFFS_SPARE_LAYOUT_SIZE);
attr->data_layout = attr->_uffs_data_layout;
attr->ecc_layout = attr->_uffs_ecc_layout;
}
#endif
#include <finsh.h>
static int nread(int argc, char **argv)
{
int ret = -1;
rt_uint8_t *spare = RT_NULL;
rt_uint8_t *data_ptr = RT_NULL;
struct rt_mtd_nand_device *device;
rt_uint32_t partition, page;
if (argc != 3)
{
LOG_E("Usage %s: %s <partition_no> <page>.\n", __func__, __func__);
goto exit_nread;
}
page = atoi(argv[2]);
partition = atoi(argv[1]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nread;
device = &mtd_partitions[partition];
data_ptr = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_PAGE_SIZE);
if (data_ptr == RT_NULL)
{
LOG_E("data_ptr: no memory\n");
goto exit_nread;
}
spare = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_OOB_SIZE);
if (spare == RT_NULL)
{
LOG_E("spare: no memory\n");
goto exit_nread;
}
rt_memset(spare, 0, SPINAND_FLASH_OOB_SIZE);
rt_memset(data_ptr, 0, SPINAND_FLASH_PAGE_SIZE);
page = page + device->block_start * device->pages_per_block;
if (spinand_read_page(device, page, &data_ptr[0], SPINAND_FLASH_PAGE_SIZE, &spare[0], SPINAND_FLASH_OOB_SIZE) != RT_EOK)
goto exit_nread;
LOG_I("Partion:%d page-%d", partition, page);
ret = 0;
exit_nread:
/* release memory */
if (data_ptr)
rt_free(data_ptr);
if (spare)
rt_free(spare);
return ret;
}
static int nwrite(int argc, char **argv)
{
int i, ret = -1;
rt_uint8_t *data_ptr = RT_NULL;
struct rt_mtd_nand_device *device;
rt_uint32_t partition, page;
if (argc != 3)
{
LOG_E("Usage %s: %s <partition_no> <page>.\n", __func__, __func__);
goto exit_nwrite;
}
partition = atoi(argv[1]);
page = atoi(argv[2]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nwrite;
device = &mtd_partitions[partition];
data_ptr = (rt_uint8_t *) rt_malloc(SPINAND_FLASH_PAGE_SIZE);
if (data_ptr == RT_NULL)
{
LOG_E("data_ptr: no memory\n");
goto exit_nwrite;
}
/* Need random data to test ECC */
for (i = 0; i < SPINAND_FLASH_PAGE_SIZE; i ++)
data_ptr[i] = i / 5 - i;
page = page + device->block_start * device->pages_per_block;
spinand_write_page(device, page, &data_ptr[0], SPINAND_FLASH_PAGE_SIZE, NULL, 0);
LOG_I("Wrote data into %d in partition-index %d.", page, partition);
ret = 0;
exit_nwrite:
/* release memory */
if (data_ptr)
rt_free(data_ptr);
return ret;
}
static int nmove(int argc, char **argv)
{
struct rt_mtd_nand_device *device;
rt_uint32_t partition, src, dst;
if (argc != 4)
{
LOG_E("Usage %s: %s <partition_no> <src page> <dst page>.\n", __func__, __func__);
goto exit_nmove;
}
partition = atoi(argv[1]);
src = atoi(argv[2]);
dst = atoi(argv[3]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
return -1;
device = &mtd_partitions[partition];
spinand_move_page(device,
src + device->block_start * device->pages_per_block,
dst + device->block_start * device->pages_per_block);
LOG_I("Move data into %d from %d in partition-index %d.", dst, src, partition);
return 0;
exit_nmove:
return -1;
}
static int nerase(int argc, char **argv)
{
struct rt_mtd_nand_device *device;
int partition, block;
if (argc != 3)
{
LOG_E("Usage %s: %s <partition_no> <block_no>.\n", __func__, __func__);
goto exit_nerase;
}
partition = atoi(argv[1]);
block = atoi(argv[2]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nerase;
device = &mtd_partitions[partition];
if (spinand_erase_block(device, block + device->block_start) != RT_EOK)
goto exit_nerase;
LOG_I("Erased block %d in partition-index %d.", block + device->block_start, partition);
return 0;
exit_nerase:
return -1;
}
static int nerase_force(int argc, char **argv)
{
struct rt_mtd_nand_device *device;
int partition, block;
if (argc != 2)
{
LOG_E("Usage %s: %s <partition_no>\n", __func__, __func__);
goto exit_nerase_force;
}
partition = atoi(argv[1]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nerase_force;
device = &mtd_partitions[partition];
for (block = 0; block <= device->block_end; block++)
{
if (spinand_erase_block_force(device, block + device->block_start) != RT_EOK)
goto exit_nerase_force;
LOG_I("Erased block %d in partition-index %d. forcely", block + device->block_start, partition);
}
return 0;
exit_nerase_force:
return -1;
}
static rt_err_t nmarkbad(int argc, char **argv)
{
struct rt_mtd_nand_device *device;
int partition, block;
if (argc != 3)
{
LOG_E("Usage %s: %s <partition_no> <block_no>.\n", __func__, __func__);
goto exit_nmarkbad;
}
partition = atoi(argv[1]);
block = atoi(argv[2]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nmarkbad;
device = &mtd_partitions[partition];
if (spinand_mark_badblock(device, block + device->block_start) != RT_EOK)
goto exit_nmarkbad;
LOG_I("Marked block %d in partition-index %d.", block + device->block_start, partition);
return 0;
exit_nmarkbad:
return -1;
}
static int nerase_all(int argc, char **argv)
{
rt_uint32_t index;
rt_uint32_t partition;
struct rt_mtd_nand_device *device;
if (argc != 2)
{
LOG_E("Usage %s: %s <partition_no>.\n", __func__, __func__);
goto exit_nerase_all;
}
partition = atoi(argv[1]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
goto exit_nerase_all;
device = &mtd_partitions[partition];
for (index = 0; index < device->block_total; index ++)
{
spinand_erase_block(device, index);
}
LOG_I("Erased all block in partition-index %d.", partition);
return 0;
exit_nerase_all:
return -1;
}
static int ncheck_all(int argc, char **argv)
{
rt_uint32_t index;
rt_uint32_t partition;
struct rt_mtd_nand_device *device;
if (argc != 2)
{
LOG_E("Usage %s: %s <partition_no>.\n", __func__, __func__);
return -1;
}
partition = atoi(argv[1]);
if (partition >= MTD_SPINAND_PARTITION_NUM)
return -1;
device = &mtd_partitions[partition];
for (index = 0; index < device->block_total; index ++)
{
LOG_I("Partion:%d Block-%d is %s", partition, index, spinand_check_block(device, index) ? "bad" : "good");
}
return 0;
}
static int nid(int argc, char **argv)
{
spinand_read_id(RT_NULL);
return 0;
}
static int nlist(int argc, char **argv)
{
rt_uint32_t index;
struct rt_mtd_nand_device *device;
rt_kprintf("\n");
for (index = 0 ; index < MTD_SPINAND_PARTITION_NUM ; index++)
{
device = &mtd_partitions[index];
rt_kprintf("[Partition #%d]\n", index);
rt_kprintf("Name: %s\n", device->parent.parent.name);
rt_kprintf("Start block: %d\n", device->block_start);
rt_kprintf("End block: %d\n", device->block_end);
rt_kprintf("Block number: %d\n", device->block_total);
rt_kprintf("Plane number: %d\n", device->plane_num);
rt_kprintf("Pages per Block: %d\n", device->pages_per_block);
rt_kprintf("Page size: %d bytes\n", device->page_size);
rt_kprintf("Spare size: %d bytes\n", device->oob_size);
rt_kprintf("Total size: %d bytes (%d KB)\n", device->block_total * device->pages_per_block * device->page_size,
device->block_total * device->pages_per_block * device->page_size / 1024);
rt_kprintf("\n");
}
return 0;
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(nid, nand id);
MSH_CMD_EXPORT(nlist, list all partition information on nand);
MSH_CMD_EXPORT(nmove, nand copy page);
MSH_CMD_EXPORT(nerase, nand erase a block of one partiton);
MSH_CMD_EXPORT(nerase_force, nand erase a block of one partiton forcely);
MSH_CMD_EXPORT(nerase_all, erase all blocks of a partition);
MSH_CMD_EXPORT(ncheck_all, check all blocks of a partition);
MSH_CMD_EXPORT(nmarkbad, nand mark bad block of one partition);
MSH_CMD_EXPORT(nwrite, nand write page);
MSH_CMD_EXPORT(nread, nand read page);
#endif
#endif

View File

@ -0,0 +1,693 @@
/**************************************************************************//**
*
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-1-13 Wayne First version
*
******************************************************************************/
#include <rtthread.h>
#if defined(NU_PKG_USING_SPINAND)
#define LOG_TAG "spinand_flash"
#define DBG_ENABLE
#define DBG_SECTION_NAME LOG_TAG
#define DBG_LEVEL DBG_INFO
#define DBG_COLOR
#include <rtdbg.h>
#include "spinand.h"
const struct nu_spinand_info g_spinandflash_list[] =
{
/* Winbond */
{ 0xEFAA21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "Winbond 128MB: 2048+64@64@1024" }, /* Only tested */
#if 0
{ 0xEFAA22, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "Winbond 256MB: 2048+64@64@1024" },
{ 0xEFAB21, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 1, "Winbond 256MB: 2048+64@64@1024, MCP" },
/* Not test and supporting yet. */
/* MXIC */
{ 0x00C212, 2048, 64, 0x6b, 0x05, 0x01, 0x40, 0x1, 1024, 64, 0, "MXIC 128MB: 2048+64@64@1024" },
/* XTX */
{ 0x0BE20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
{ 0x0BF20B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 2048, 64, 0, "XTX 256MB: 2048+64@64@2048" },
{ 0x0BE10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
{ 0x0BF10B, 2048, 64, 0x6b, 0xff, 0xff, 0xff, 0x1, 1024, 64, 0, "XTX 256MB: 2048+64@64@1024" },
/* ATO */
{ 0x9B129B, 2048, 64, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "ATO 128MB: 2048+64@64@1024" },
/* Micro */
{ 0x2C242C, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 2048, 64, 0, "Micro 256MB: 2048+128@64@2048" },
/* GigaDevice */
{ 0xB148C8, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "GD 128MB: 2048+128@64@1024" },
/* Unknown */
{ 0x00C8D1, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
{ 0x00C851, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" },
{ 0x98E240, 2048, 128, 0x6b, 0x0f, 0x1f, 0x01, 0x1, 1024, 64, 0, "Unknown 128MB: 2048+128@64@1024" }
#endif
};
#define SPINAND_LIST_ELEMENT_NUM ( sizeof(g_spinandflash_list)/sizeof(struct nu_spinand_info) )
/*
For 0xEFAA21 description:
Data Area(2048-Byte)
-----------------------------
|Sect-0|Sect-1|Sect-2|Sect-3|
|(512B)|(512B)|(512B)|(512B)|
-----------------------------
Spare Area(64-Byte)
---------------------------------
|Spare-0|Spare-1|Spare-2|Spare-3|
| (16B) | (16B) | (16B) | (16B) |
---------------------------------
----------------- Spare-0 -------------------
/ \
-------------------------------------------------
| BBM | UD2 | UD1 | ECC Sect-0 | ECC Spare |
| 0 1 | 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
-------------------------------------------------
| NO ECC | ECC PROTECTED | ECC 4-D |
BBM: Bad block marker.
UD1: User Data 1.
UD2: User Data 2.
ECC Sect-n: ECC for sector-n.
ECC Spare: ECC for spare 4-D.
---------------- Spare-1 -------------------
/ \
-----------------------------------------------
| UD2 | UD1 | ECC Sect-1 | ECC Spare |
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
-----------------------------------------------
| NO ECC | ECC PROTECTED | ECC 14-1D |
---------------- Spare-2 -------------------
/ \
-----------------------------------------------
| UD2 | UD1 | ECC Sect-2 | ECC Spare |
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
-----------------------------------------------
| NO ECC | ECC PROTECTED | ECC 24-2D |
---------------- Spare-3 -------------------
/ \
-----------------------------------------------
| UD2 | UD1 | ECC Sect-3 | ECC Spare |
| 0 1 2 3 | 4 5 6 7 | 8 9 A B C D | E F |
-----------------------------------------------
| NO ECC | ECC PROTECTED | ECC 34-3D |
*/
rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE] =
{
#if defined(RT_USING_DFS_UFFS)
/* For storing Seal-byte at 0x37. */
0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x03, 0xFF, 0x00
#else
0x04, 0x04, 0x14, 0x04, 0x24, 0x04, 0x34, 0x04, 0xFF, 0x00
#endif
};
rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE] =
{
#if defined(RT_USING_DFS_UFFS)
/* For storing Seal-byte at 0x37 and not report latest ECC part in Spare-3 */
0x08, 0x08, 0x18, 0x08, 0x28, 0x08, /*0x38, 0x08,*/ 0xFF, 0x00
#else
0x08, 0x08, 0x18, 0x08, 0x28, 0x08, 0x38, 0x08, 0xFF, 0x00
#endif
};
static rt_err_t spinand_info_read(struct rt_qspi_device *qspi);
static rt_err_t spinand_die_select(struct rt_qspi_device *qspi, uint8_t select_die)
{
uint8_t au8Cmd[2] = { 0xC2, 0x0 };
au8Cmd[1] = select_die;
return nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd));
}
static uint8_t spinand_isbusy(struct rt_qspi_device *qspi)
{
#define BUSY_CKECKING_TIMEOUT_MS 3000
volatile uint8_t SR = 0xFF;
rt_err_t result;
uint8_t au8Cmd[2] = { 0x0F, 0xC0 };
uint32_t u32CheckingDuration = rt_tick_from_millisecond(BUSY_CKECKING_TIMEOUT_MS);
uint32_t u32Start = rt_tick_get();
do
{
result = nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), (void *)&SR, 1);
if (result != RT_EOK)
goto timeout_spinand_isbusy;
if ((rt_tick_get() - u32Start) >= u32CheckingDuration)
{
goto timeout_spinand_isbusy;
}
}
while ((SR & 0x1) != 0x00);
return 0;
timeout_spinand_isbusy:
LOG_E("Error: spinand timeout.");
return 1;
}
static rt_err_t spinand_program_dataload(
struct rt_qspi_device *qspi,
uint8_t u8AddrH,
uint8_t u8AddrL,
uint8_t *pu8DataBuff,
uint32_t u32DataCount,
uint8_t *pu8SpareBuff,
uint32_t u32SpareCount)
{
uint32_t volatile i = 0;
uint8_t u8WECmd = 0x06;
rt_err_t result = RT_EOK;
struct rt_qspi_message qspi_messages[2] = {0};
/* 1-bit mode */
qspi_messages[0].instruction.content = 0x32;
qspi_messages[0].instruction.qspi_lines = 1;
qspi_messages[0].address.content = (u8AddrH << 8) | (u8AddrL);
qspi_messages[0].address.size = 2 * 8;
qspi_messages[0].address.qspi_lines = 1;
/* 4-bit mode */
qspi_messages[0].qspi_data_lines = 4;
qspi_messages[0].parent.cs_take = 1;
qspi_messages[0].parent.cs_release = 0;
qspi_messages[0].parent.send_buf = pu8DataBuff;
qspi_messages[0].parent.length = u32DataCount;
qspi_messages[0].parent.next = &qspi_messages[1].parent;
qspi_messages[1].qspi_data_lines = 4;
qspi_messages[1].parent.cs_take = 0;
qspi_messages[1].parent.cs_release = 1;
qspi_messages[1].parent.send_buf = pu8SpareBuff;
qspi_messages[1].parent.length = u32SpareCount;
if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
goto exit_spinand_program_dataload;
result = nu_qspi_transfer_message(qspi, (struct rt_qspi_message *)&qspi_messages[0]);
exit_spinand_program_dataload:
return result;
}
static uint8_t spinand_status_register_read(struct rt_qspi_device *qspi, uint8_t u8SRSel)
{
uint8_t u8SR = 0;
uint8_t au8Cmd[2];
switch (u8SRSel)
{
case 0x01:
au8Cmd[0] = 0x05;
au8Cmd[1] = 0xA0;
break;
case 0x02:
au8Cmd[0] = 0x0F;
au8Cmd[1] = 0xB0;
break;
case 0x03:
au8Cmd[0] = 0x05;
au8Cmd[1] = 0xC0;
break;
default:
RT_ASSERT(0);
break;
}
if (nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), &u8SR, 1) != RT_EOK)
RT_ASSERT(0);
return u8SR;
}
static rt_err_t spinand_status_register_write(struct rt_qspi_device *qspi, uint8_t u8SRSel, uint8_t u8Value)
{
rt_err_t result = RT_EOK;
uint8_t au8Cmd[3];
switch (u8SRSel)
{
case 0x01:
au8Cmd[0] = 0x01;
au8Cmd[1] = 0xA0;
break;
case 0x02:
au8Cmd[0] = 0x01;
au8Cmd[1] = 0xB0;
break;
case 0x03:
au8Cmd[0] = 0x01;
au8Cmd[1] = 0xC0;
break;
default:
result = RT_EINVAL;
goto exit_spinand_status_register_write;
}
au8Cmd[2] = u8Value;
if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
goto exit_spinand_status_register_write;
if (spinand_isbusy(qspi))
{
result = RT_EIO;
goto exit_spinand_status_register_write;
}
exit_spinand_status_register_write:
return result;
}
static rt_err_t spinand_program_execute(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
{
rt_err_t result;
uint8_t au8Cmd[4], u8SR;
au8Cmd[0] = 0x10 ;
au8Cmd[1] = u8Addr2;
au8Cmd[2] = u8Addr1;
au8Cmd[3] = u8Addr0;
if ((result = nu_qspi_send(qspi, &au8Cmd, sizeof(au8Cmd))) != RT_EOK)
goto exit_spinand_program_execute;
if (spinand_isbusy(qspi))
{
result = -RT_MTD_EIO;
goto exit_spinand_program_execute;
}
u8SR = (spinand_status_register_read(SPINAND_FLASH_QSPI, 3) & 0x0C) >> 2;
if (u8SR == 1)
{
result = -RT_MTD_EIO;
LOG_E("Error write status!");
}
exit_spinand_program_execute:
return result;
}
static rt_err_t spinand_normal_read(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8Buff, uint32_t u32Count)
{
uint8_t au8Cmd[4];
au8Cmd[0] = 0x03;
au8Cmd[1] = u8AddrH;
au8Cmd[2] = u8AddrL;
au8Cmd[3] = 0x00;
return nu_qspi_send_then_recv(qspi, &au8Cmd[0], sizeof(au8Cmd), pu8Buff, u32Count);
}
static rt_err_t spinand_protect_set(struct rt_qspi_device *qspi, uint8_t u8Protect)
{
/* Read status register 1 */
uint8_t u8SR = spinand_status_register_read(qspi, 1);
if (u8Protect)
{
/* protect */
u8SR |= 0x7C;
}
else
{
/* unprotect */
u8SR &= 0x83;
}
return spinand_status_register_write(qspi, 1, u8SR);
}
static uint8_t spinand_program_erase_isfail(struct rt_qspi_device *qspi)
{
/* Read status register 3 */
uint8_t u8SR = spinand_status_register_read(qspi, 3);
return (u8SR & 0x0C) >> 2; /* Check P-Fail, E-Fail bit */
}
static uint8_t spinand_hwecc_status_get(struct rt_qspi_device *qspi)
{
/* Read status register 3 */
uint8_t u8SR = spinand_status_register_read(qspi, 3);
return (u8SR & 0x30) >> 4; /* ECC-1, ECC0 bit */
}
static rt_err_t spinand_hwecc_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
{
uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
if (u8Enable)
{
u8SR |= 0x10; // Enable ECC-E bit
}
else
{
u8SR &= 0xEF; // Disable ECC-E bit
}
return spinand_status_register_write(qspi, 2, u8SR);
}
static uint8_t spinand_hwecc_get(struct rt_qspi_device *qspi)
{
/* Read status register 2 */
uint8_t u8SR = spinand_status_register_read(qspi, 2);
return (u8SR & 0x10) >> 4;
}
static rt_err_t spinand_read_dataload(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
{
rt_err_t result = RT_EOK;
uint8_t au8Cmd[4];
uint8_t u8SR;
au8Cmd[0] = 0x13 ;
au8Cmd[1] = u8Addr2;
au8Cmd[2] = u8Addr1;
au8Cmd[3] = u8Addr0;
if ((result = nu_qspi_send(qspi, &au8Cmd[0], sizeof(au8Cmd))) != RT_EOK)
goto exit_spinand_read_dataload;
if (spinand_isbusy(qspi))
{
result = -RT_EIO;
goto exit_spinand_read_dataload;
}
u8SR = spinand_hwecc_status_get(SPINAND_FLASH_QSPI);
if ((u8SR != 0x00) && (u8SR != 0x01))
{
result = -RT_MTD_EECC;
LOG_E("Error ECC status error[0x%x].", u8SR);
}
exit_spinand_read_dataload:
return result;
}
static uint8_t spinand_block_isbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
{
rt_err_t result;
uint8_t read_buf;
again_spinand_block_isbad:
result = spinand_read_dataload(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF); // Read the first page of a block
RT_ASSERT(result == RT_EOK);
result = spinand_normal_read(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &read_buf, 1); // Read bad block mark at 0x800 update at v.1.0.8
RT_ASSERT(result == RT_EOK);
if (read_buf != 0xFF)
{
// update at v.1.0.7
return 1;
}
if (((u32PageAddr % (SPINAND_FLASH_PAGE_PER_BLOCK_NUM * SPINAND_FLASH_PAGE_SIZE)) == 0))
{
/* Need check second page again. */
u32PageAddr++;
goto again_spinand_block_isbad;
}
return 0;
}
static rt_err_t spinand_buffermode_set(struct rt_qspi_device *qspi, uint8_t u8Enable)
{
uint8_t u8SR = spinand_status_register_read(qspi, 2); // Read status register 2
if (u8Enable)
{
u8SR |= 0x08; // Enable BUF bit
}
else
{
u8SR &= 0xF7; // Disable BUF bit
}
return spinand_status_register_write(qspi, 2, u8SR);
}
static rt_err_t spinand_block_erase(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0)
{
rt_err_t result;
uint8_t u8WECmd = 0x06;
uint8_t au8EraseCmd[4], u8SR;
au8EraseCmd[0] = 0xD8;
au8EraseCmd[1] = u8Addr2;
au8EraseCmd[2] = u8Addr1;
au8EraseCmd[3] = u8Addr0;
if ((result = nu_qspi_send(qspi, &u8WECmd, sizeof(u8WECmd))) != RT_EOK)
goto exit_spinand_block_erase;
if ((result = nu_qspi_send(qspi, &au8EraseCmd[0], sizeof(au8EraseCmd))) != RT_EOK)
goto exit_spinand_block_erase;
if (spinand_isbusy(qspi))
return -RT_EIO;
u8SR = spinand_program_erase_isfail(SPINAND_FLASH_QSPI);
if (u8SR != 0)
{
/* Fail to erase */
LOG_E("Fail to erase. Will mark it bad.");
result = -RT_ERROR;
goto exit_spinand_block_erase;
}
exit_spinand_block_erase:
return result;
}
static rt_err_t spinand_block_markbad(struct rt_qspi_device *qspi, uint32_t u32PageAddr)
{
rt_err_t result = RT_EOK;
uint8_t u8BadBlockMarker = 0xF0;
result = spinand_block_erase(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
if (result != RT_EOK)
return result;
result = spinand_program_dataload(qspi, (SPINAND_FLASH_PAGE_SIZE >> 8) & 0xff, SPINAND_FLASH_PAGE_SIZE & 0xff, &u8BadBlockMarker, 1, 0, 0);
if (result != RT_EOK)
return result;
return spinand_program_execute(qspi, (u32PageAddr >> 16) & 0xFF, (u32PageAddr >> 8) & 0xFF, u32PageAddr & 0xFF);
}
static rt_err_t spinand_read_quadoutput(
struct rt_qspi_device *qspi,
uint8_t u8AddrH,
uint8_t u8AddrL,
uint8_t *pu8DataBuff,
uint32_t u32DataCount
)
{
struct rt_qspi_message qspi_messages = {0};
/* 1-bit mode */
qspi_messages.instruction.content = SPINAND_FLASH_QUADREAD_CMDID;
qspi_messages.instruction.qspi_lines = 1;
qspi_messages.address.content = (u8AddrH << 8) | (u8AddrL);
qspi_messages.address.size = 2 * 8;
qspi_messages.address.qspi_lines = 1;
qspi_messages.dummy_cycles = SPINAND_FLASH_DUMMYBYTE * 8; //In bit
/* 4-bit mode */
qspi_messages.qspi_data_lines = 4;
qspi_messages.parent.cs_take = 1;
qspi_messages.parent.cs_release = 1;
qspi_messages.parent.recv_buf = pu8DataBuff;
qspi_messages.parent.length = u32DataCount;
qspi_messages.parent.next = RT_NULL;
return nu_qspi_transfer_message(qspi, (struct rt_qspi_message *) &qspi_messages);
}
static rt_err_t spinand_jedecid_get(struct rt_qspi_device *qspi, uint32_t *pu32ID)
{
uint32_t u32JedecId = 0;
uint32_t u32JedecId_real = 0;
uint8_t u8Cmd = 0x9F;
if (nu_qspi_send_then_recv(qspi, &u8Cmd, 1, &u32JedecId, 4) != RT_EOK)
{
return -RT_ERROR;
}
/* Reverse order. */
nu_set32_be((uint8_t *)&u32JedecId_real, u32JedecId);
/* Only keep 3-bytes. */
u32JedecId_real &= 0x00ffffff;
*pu32ID = u32JedecId_real;
return RT_EOK;
}
static rt_err_t spinand_reset(struct rt_qspi_device *qspi)
{
rt_err_t result;
uint8_t u8Cmd = 0xFF;
if ((result = nu_qspi_send(qspi, &u8Cmd, 1)) != RT_EOK)
goto exit_spinand_reset;
if (spinand_isbusy(qspi))
{
result = RT_EIO;
goto exit_spinand_reset;
}
exit_spinand_reset:
return result;
}
rt_err_t spinand_flash_init(struct rt_qspi_device *qspi)
{
rt_err_t result;
if ((result = spinand_reset(qspi)) != RT_EOK)
goto exit_spinand_init;
if ((result = spinand_info_read(qspi)) != RT_EOK)
goto exit_spinand_init;
/* Un-protect */
if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
goto exit_spinand_init;
/* Enable BUF mode */
if ((result = spinand_buffermode_set(qspi, 1)) != RT_EOK)
goto exit_spinand_init;
/* Enable HWECC */
if ((result = spinand_hwecc_set(qspi, 1)) != RT_EOK)
goto exit_spinand_init;
/* Check HWECC */
if (!(spinand_hwecc_get(qspi)))
goto exit_spinand_init;
if (SPINAND_FLASH_MCP == 1)
{
/* Select die. */
if ((result = spinand_die_select(qspi, SPINAND_DIE_ID1)) != RT_EOK)
goto exit_spinand_init;
/* Unprotect */
if ((result = spinand_protect_set(qspi, 0)) != RT_EOK)
goto exit_spinand_init;
}
LOG_I("Enabled BUF, HWECC. Unprotected.");
exit_spinand_init:
return -result;
}
struct spinand_ops spinand_ops_wb =
{
.block_erase = spinand_block_erase,
.block_isbad = spinand_block_isbad,
.block_markbad = spinand_block_markbad,
.die_select = spinand_die_select,
.jedecid_get = spinand_jedecid_get,
.program_dataload = spinand_program_dataload,
.program_execute = spinand_program_execute,
.read_dataload = spinand_read_dataload,
.read_quadoutput = spinand_read_quadoutput
};
static rt_err_t spinand_info_read(struct rt_qspi_device *qspi)
{
int i;
uint32_t u32JedecId = 0;
if (spinand_jedecid_get(qspi, &u32JedecId) != RT_EOK)
goto exit_spinand_info_read;
for (i = 0 ; i < SPINAND_LIST_ELEMENT_NUM; i++)
{
if (u32JedecId == g_spinandflash_list[i].u32JEDECID) /* Match JEDECID? */
{
rt_memcpy(SPINAND_FLASH_INFO, &g_spinandflash_list[i], sizeof(struct nu_spinand_info));
LOG_I("Found: [%08X] %s.", u32JedecId, SPINAND_FLASH_DESCRIPTION);
switch (u32JedecId & 0xff0000)
{
case 0xEF0000: /* Winbond */
SPINAND_FLASH_OPS = &spinand_ops_wb;
break;
default:
goto exit_spinand_info_read;
}
return RT_EOK;
}
}
exit_spinand_info_read:
LOG_E("Can't find the flash[%08X] in supported list.", u32JedecId);
return -RT_ERROR;
}
#endif

View File

@ -0,0 +1,95 @@
/**************************************************************************//**
*
* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-1-13 Wayne First version
*
******************************************************************************/
#ifndef __SPINAND_H__
#define __SPINAND_H__
#include <rtthread.h>
#include <drivers/mtd_nand.h>
#include "drv_spi.h"
#include <board.h>
/* SPI NAND flash information */
struct nu_spinand_info
{
uint32_t u32JEDECID;
uint16_t u16PageSize;
uint16_t u16OOBSize;
uint8_t u8QuadReadCmdId;
uint8_t u8ReadStatusCmdId;
uint8_t u8WriteStatusCmdid;
uint8_t u8StatusValue;
uint8_t u8DummyByte;
uint32_t u32BlockPerFlash;
uint32_t u32PagePerBlock;
uint8_t u8IsDieSelect;
const char *szDescription;
};
typedef struct nu_spinand_info *nu_spinand_info_t;
struct spinand_ops
{
rt_err_t (*block_erase)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
uint8_t (*block_isbad)(struct rt_qspi_device *qspi, uint32_t u32PageAddr);
rt_err_t (*block_markbad)(struct rt_qspi_device *qspi, uint32_t u32PageAddr);
rt_err_t (*die_select)(struct rt_qspi_device *qspi, uint8_t select_die);
rt_err_t (*jedecid_get)(struct rt_qspi_device *qspi, uint32_t *pu32ID);
rt_err_t (*program_dataload)(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8DataBuff,
uint32_t u32DataCount, uint8_t *pu8SpareBuff, uint32_t u32SpareCount);
rt_err_t (*program_execute)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
rt_err_t (*read_dataload)(struct rt_qspi_device *qspi, uint8_t u8Addr2, uint8_t u8Addr1, uint8_t u8Addr0);
rt_err_t (*read_quadoutput)(struct rt_qspi_device *qspi, uint8_t u8AddrH, uint8_t u8AddrL, uint8_t *pu8DataBuff, uint32_t u32DataCount);
};
typedef struct spinand_ops *nu_spinand_ops_t;
struct nu_spinand
{
struct nu_spinand_info info;
struct rt_qspi_device *qspi_device;
nu_spinand_ops_t ops;
struct rt_mutex lock;
};
typedef struct nu_spinand *nu_spinand_t;
#define SPINAND_FLASH_JEDECID g_spinandflash_dev.info.u32JEDECID
#define SPINAND_FLASH_PAGE_SIZE g_spinandflash_dev.info.u16PageSize
#define SPINAND_FLASH_OOB_SIZE g_spinandflash_dev.info.u16OOBSize
#define SPINAND_FLASH_QUADREAD_CMDID g_spinandflash_dev.info.u8QuadReadCmdId
#define SPINAND_FLASH_DUMMYBYTE g_spinandflash_dev.info.u8DummyByte
#define SPINAND_FLASH_BLOCK_NUM g_spinandflash_dev.info.u32BlockPerFlash
#define SPINAND_FLASH_PAGE_PER_BLOCK_NUM g_spinandflash_dev.info.u32PagePerBlock
#define SPINAND_FLASH_DESCRIPTION g_spinandflash_dev.info.szDescription
#define SPINAND_FLASH_MCP g_spinandflash_dev.info.u8IsDieSelect
#define SPINAND_FLASH_INFO &g_spinandflash_dev.info
#define SPINAND_FLASH_QSPI g_spinandflash_dev.qspi_device
#define SPINAND_FLASH_LOCK &g_spinandflash_dev.lock
#define SPINAND_FLASH_OPS g_spinandflash_dev.ops
#define SPINAND_DIE_ID0 (0)
#define SPINAND_DIE_ID1 (1)
#define SPINAND_SPARE_LAYOUT_SIZE 16
rt_err_t rt_hw_mtd_spinand_register(const char *device_name);
rt_size_t nu_qspi_transfer_message(struct rt_qspi_device *device, struct rt_qspi_message *message);
rt_err_t nu_qspi_send_then_recv(struct rt_qspi_device *device, const void *send_buf, rt_size_t send_length, void *recv_buf, rt_size_t recv_length);
rt_err_t nu_qspi_send(struct rt_qspi_device *device, const void *send_buf, rt_size_t length);
rt_err_t spinand_flash_init(struct rt_qspi_device *qspi);
extern struct nu_spinand g_spinandflash_dev;
extern rt_uint8_t spinand_flash_data_layout[SPINAND_SPARE_LAYOUT_SIZE];
extern rt_uint8_t spinand_flash_ecc_layout[SPINAND_SPARE_LAYOUT_SIZE];
#endif /* __SPINAND_H__ */

View File

@ -46,45 +46,45 @@
typedef struct
{
uint32_t CREQ; /*!< [0x0020] IFn Command Request Register */
uint32_t CMASK; /*!< [0x0024] IFn Command Mask Register */
uint32_t MASK1; /*!< [0x0028] IFn Mask 1 Register */
uint32_t MASK2; /*!< [0x002c] IFn Mask 2 Register */
uint32_t ARB1; /*!< [0x0030] IFn Arbitration 1 Register */
uint32_t ARB2; /*!< [0x0034] IFn Arbitration 2 Register */
uint32_t MCON; /*!< [0x0038] IFn Message Control Register */
uint32_t DAT_A1; /*!< [0x003c] IFn Data A1 Register */
uint32_t DAT_A2; /*!< [0x0040] IFn Data A2 Register */
uint32_t DAT_B1; /*!< [0x0044] IFn Data B1 Register */
uint32_t DAT_B2; /*!< [0x0048] IFn Data B2 Register */
uint32_t RESERVE0[13];
__IO uint32_t CREQ; /*!< [0x0020] IFn Command Request Register */
__IO uint32_t CMASK; /*!< [0x0024] IFn Command Mask Register */
__IO uint32_t MASK1; /*!< [0x0028] IFn Mask 1 Register */
__IO uint32_t MASK2; /*!< [0x002c] IFn Mask 2 Register */
__IO uint32_t ARB1; /*!< [0x0030] IFn Arbitration 1 Register */
__IO uint32_t ARB2; /*!< [0x0034] IFn Arbitration 2 Register */
__IO uint32_t MCON; /*!< [0x0038] IFn Message Control Register */
__IO uint32_t DAT_A1; /*!< [0x003c] IFn Data A1 Register */
__IO uint32_t DAT_A2; /*!< [0x0040] IFn Data A2 Register */
__IO uint32_t DAT_B1; /*!< [0x0044] IFn Data B1 Register */
__IO uint32_t DAT_B2; /*!< [0x0048] IFn Data B2 Register */
__I uint32_t RESERVE0[13];
} CAN_IF_T;
typedef struct
{
uint32_t CON; /*!< [0x0000] Control Register */
uint32_t STATUS; /*!< [0x0004] Status Register */
uint32_t ERR; /*!< [0x0008] Error Counter Register */
uint32_t BTIME; /*!< [0x000c] Bit Timing Register */
uint32_t IIDR; /*!< [0x0010] Interrupt Identifier Register */
uint32_t TEST; /*!< [0x0014] Test Register */
uint32_t BRPE; /*!< [0x0018] Baud Rate Prescaler Extension Register */
uint32_t RESERVE0[1];
CAN_IF_T IF[2];
uint32_t RESERVE2[8];
uint32_t TXREQ1; /*!< [0x0100] Transmission Request Register 1 */
uint32_t TXREQ2; /*!< [0x0104] Transmission Request Register 2 */
uint32_t RESERVE3[6];
uint32_t NDAT1; /*!< [0x0120] New Data Register 1 */
uint32_t NDAT2; /*!< [0x0124] New Data Register 2 */
uint32_t RESERVE4[6];
uint32_t IPND1; /*!< [0x0140] Interrupt Pending Register 1 */
uint32_t IPND2; /*!< [0x0144] Interrupt Pending Register 2 */
uint32_t RESERVE5[6];
uint32_t MVLD1; /*!< [0x0160] Message Valid Register 1 */
uint32_t MVLD2; /*!< [0x0164] Message Valid Register 2 */
uint32_t WU_EN; /*!< [0x0168] Wake-up Enable Control Register */
uint32_t WU_STATUS; /*!< [0x016c] Wake-up Status Register */
__IO uint32_t CON; /*!< [0x0000] Control Register */
__IO uint32_t STATUS; /*!< [0x0004] Status Register */
__I uint32_t ERR; /*!< [0x0008] Error Counter Register */
__IO uint32_t BTIME; /*!< [0x000c] Bit Timing Register */
__I uint32_t IIDR; /*!< [0x0010] Interrupt Identifier Register */
__IO uint32_t TEST; /*!< [0x0014] Test Register */
__IO uint32_t BRPE; /*!< [0x0018] Baud Rate Prescaler Extension Register */
__I uint32_t RESERVE0[1];
__IO CAN_IF_T IF[2];
__I uint32_t RESERVE2[8];
__I uint32_t TXREQ1; /*!< [0x0100] Transmission Request Register 1 */
__I uint32_t TXREQ2; /*!< [0x0104] Transmission Request Register 2 */
__I uint32_t RESERVE3[6];
__I uint32_t NDAT1; /*!< [0x0120] New Data Register 1 */
__I uint32_t NDAT2; /*!< [0x0124] New Data Register 2 */
__I uint32_t RESERVE4[6];
__I uint32_t IPND1; /*!< [0x0140] Interrupt Pending Register 1 */
__I uint32_t IPND2; /*!< [0x0144] Interrupt Pending Register 2 */
__I uint32_t RESERVE5[6];
__I uint32_t MVLD1; /*!< [0x0160] Message Valid Register 1 */
__I uint32_t MVLD2; /*!< [0x0164] Message Valid Register 2 */
__IO uint32_t WU_EN; /*!< [0x0168] Wake-up Enable Control Register */
__IO uint32_t WU_STATUS; /*!< [0x016c] Wake-up Status Register */
} CAN_T;

View File

@ -647,6 +647,42 @@ static __inline void ETIMER_ClearCaptureIntFlag(UINT timer)
}
}
/**
* @brief This function gets the Timer capture falling edge flag.
* @param[in] timer ETIMER number. Range from 0 ~ 5
* @return None
*/
static __inline UINT8 ETIMER_GetCaptureFallingEdgeFlag(UINT timer)
{
UINT ret;
if (timer == 0)
{
ret = inpw(REG_ETMR0_ISR);
}
else if (timer == 1)
{
ret = inpw(REG_ETMR1_ISR);
}
else if (timer == 2)
{
ret = inpw(REG_ETMR2_ISR);
}
else if (timer == 3)
{
ret = inpw(REG_ETMR3_ISR);
}
else if (timer == 4)
{
ret = inpw(REG_ETMR4_ISR);
}
else
{
ret = inpw(REG_ETMR5_ISR);
}
return (ret & (1 << 6)) >> 6;
}
/**
* @brief This function indicates Timer has waked up system or not.
* @param[in] timer ETIMER number. Range from 0 ~ 5

View File

@ -110,23 +110,23 @@ typedef struct
typedef struct
{
uint32_t INIT; /*!< [0x0000] RTC Initiation Register */
uint32_t RWEN; /*!< [0x0004] RTC Access Enable Register */
uint32_t FREQADJ; /*!< [0x0008] RTC Frequency Compensation Register */
uint32_t TIME; /*!< [0x000c] RTC Time Loading Register */
uint32_t CAL; /*!< [0x0010] RTC Calendar Loading Register */
uint32_t CLKFMT; /*!< [0x0014] RTC Time Scale Selection Register */
uint32_t WEEKDAY; /*!< [0x0018] RTC Day of the Week Register */
uint32_t TALM; /*!< [0x001c] RTC Time Alarm Register */
uint32_t CALM; /*!< [0x0020] RTC Calendar Alarm Register */
uint32_t LEAPYEAR; /*!< [0x0024] RTC Leap Year Indicator Register */
uint32_t INTEN; /*!< [0x0028] RTC Interrupt Enable Register */
uint32_t INTSTS; /*!< [0x002c] RTC Interrupt Status Register */
uint32_t TICK; /*!< [0x0030] RTC Time Tick Register */
uint32_t PWRCTL; /*!< [0x0034] RTC Power Control Register */
uint32_t PWRCNT; /*!< [0x0038] RTC Power Control Counter Register */
uint32_t RESERVE0; /*!< [0x003c] RTC Spare Functional Control Register */
uint32_t SPR[16]; /*!< [0x0040] ~ [0x007c] RTC Spare Register 0 ~ 15 */
__IO uint32_t INIT; /*!< [0x0000] RTC Initiation Register */
__IO uint32_t RWEN; /*!< [0x0004] RTC Access Enable Register */
__IO uint32_t FREQADJ; /*!< [0x0008] RTC Frequency Compensation Register */
__IO uint32_t TIME; /*!< [0x000c] RTC Time Loading Register */
__IO uint32_t CAL; /*!< [0x0010] RTC Calendar Loading Register */
__IO uint32_t CLKFMT; /*!< [0x0014] RTC Time Scale Selection Register */
__IO uint32_t WEEKDAY; /*!< [0x0018] RTC Day of the Week Register */
__IO uint32_t TALM; /*!< [0x001c] RTC Time Alarm Register */
__IO uint32_t CALM; /*!< [0x0020] RTC Calendar Alarm Register */
__I uint32_t LEAPYEAR; /*!< [0x0024] RTC Leap Year Indicator Register */
__IO uint32_t INTEN; /*!< [0x0028] RTC Interrupt Enable Register */
__IO uint32_t INTSTS; /*!< [0x002c] RTC Interrupt Status Register */
__IO uint32_t TICK; /*!< [0x0030] RTC Time Tick Register */
__IO uint32_t PWRCTL; /*!< [0x0034] RTC Power Control Register */
__IO uint32_t PWRCNT; /*!< [0x0038] RTC Power Control Counter Register */
__IO uint32_t RESERVE0; /*!< [0x003c] RTC Spare Functional Control Register */
__I uint32_t SPR[16]; /*!< [0x0040] ~ [0x007c] RTC Spare Register 0 ~ 15 */
} RTC_T;
#define RTC_INIT_ACTIVE_Pos (0) /*!< RTC_T::INIT: INIT_ACTIVE Position */

View File

@ -116,25 +116,25 @@
typedef struct
{
uint32_t DAT; /*!< [0x0000] UART Receive/Transmit Buffer Register */
uint32_t INTEN; /*!< [0x0004] UART Interrupt Enable Register */
uint32_t FIFO; /*!< [0x0008] UART FIFO Control Register */
uint32_t LINE; /*!< [0x000c] UART Line Control Register */
uint32_t MODEM; /*!< [0x0010] UART Modem Control Register */
uint32_t MODEMSTS; /*!< [0x0014] UART Modem Status Register */
uint32_t FIFOSTS; /*!< [0x0018] UART FIFO Status Register */
uint32_t INTSTS; /*!< [0x001c] UART Interrupt Status Register */
uint32_t TOUT; /*!< [0x0020] UART Time-out Register */
uint32_t BAUD; /*!< [0x0024] UART Baud Rate Divider Register */
uint32_t IRDA; /*!< [0x0028] UART IrDA Control Register */
uint32_t ALTCTL; /*!< [0x002c] UART Alternate Control/Status Register */
uint32_t FUNCSEL; /*!< [0x0030] UART Function Select Register */
uint32_t LINCTL; /*!< [0x0034] UART LIN Control Register */
uint32_t LINSTS; /*!< [0x0038] UART LIN Status Register */
uint32_t BRCOMP; /*!< [0x003c] UART Baud Rate Compensation Register */
uint32_t WKCTL; /*!< [0x0040] UART Wake-up Control Register */
uint32_t WKSTS; /*!< [0x0044] UART Wake-up Status Register */
uint32_t DWKCOMP; /*!< [0x0048] UART Incoming Data Wake-up Compensation Register */
__IO uint32_t DAT; /*!< [0x0000] UART Receive/Transmit Buffer Register */
__IO uint32_t INTEN; /*!< [0x0004] UART Interrupt Enable Register */
__IO uint32_t FIFO; /*!< [0x0008] UART FIFO Control Register */
__IO uint32_t LINE; /*!< [0x000c] UART Line Control Register */
__IO uint32_t MODEM; /*!< [0x0010] UART Modem Control Register */
__IO uint32_t MODEMSTS; /*!< [0x0014] UART Modem Status Register */
__IO uint32_t FIFOSTS; /*!< [0x0018] UART FIFO Status Register */
__IO uint32_t INTSTS; /*!< [0x001c] UART Interrupt Status Register */
__IO uint32_t TOUT; /*!< [0x0020] UART Time-out Register */
__IO uint32_t BAUD; /*!< [0x0024] UART Baud Rate Divider Register */
__IO uint32_t IRDA; /*!< [0x0028] UART IrDA Control Register */
__IO uint32_t ALTCTL; /*!< [0x002c] UART Alternate Control/Status Register */
__IO uint32_t FUNCSEL; /*!< [0x0030] UART Function Select Register */
__IO uint32_t LINCTL; /*!< [0x0034] UART LIN Control Register */
__IO uint32_t LINSTS; /*!< [0x0038] UART LIN Status Register */
__IO uint32_t BRCOMP; /*!< [0x003c] UART Baud Rate Compensation Register */
__IO uint32_t WKCTL; /*!< [0x0040] UART Wake-up Control Register */
__IO uint32_t WKSTS; /*!< [0x0044] UART Wake-up Status Register */
__IO uint32_t DWKCOMP; /*!< [0x0048] UART Incoming Data Wake-up Compensation Register */
} UART_T;

View File

@ -18,9 +18,9 @@ if not GetDepend('BSP_USE_STDDRIVER_SOURCE'):
libs += ['libstddriver_gcc']
if not libs:
group = DefineGroup('nuc980_driver', src, depend = [''], CPPPATH = cpppath)
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = cpppath)
else:
src = []
group = DefineGroup('nuc980_driver', src, depend = [''], CPPPATH = cpppath, LIBS = libs, LIBPATH = libpath)
group = DefineGroup('Libraries', src, depend = [''], CPPPATH = cpppath, LIBS = libs, LIBPATH = libpath)
Return('group')

View File

@ -16,6 +16,7 @@
| QSPI | RT_Device_Class_SPIBUS | ***qspi[0]*** |
| RTC | RT_Device_Class_RTC | ***rtc*** |
| PWM | RT_Device_Class_Miscellaneous (PWM) | ***pwm[0-1]*** |
| USBH | RT_Device_Class_USBHost | ***usbh*** |
| USBD | RT_Device_Class_USBDevice | ***usbd*** |
| SC (UART function) | RT_Device_Class_Char | ***scuart[0-1]*** |
| SDH | RT_Device_Class_Block | ***sdh[0-1]*** |

View File

@ -0,0 +1,12 @@
# RT-Thread building script for component
from building import *
cwd = GetCurrentDir()
group = []
if GetDepend('BSP_USING_HSUSBH') or GetDepend('BSP_USING_USBH'):
src = Glob('*src/*.c') + Glob('src/*.cpp')
CPPPATH = [cwd + '/inc']
group = DefineGroup('nuc980_usbhostlib', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,279 @@
/**************************************************************************//**
* @file ehci.h
* @version V1.00
* @brief USB EHCI host controller driver header file.
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef _USBH_EHCI_H_
#define _USBH_EHCI_H_
/// @cond HIDDEN_SYMBOLS
struct utr_t;
struct udev_t;
struct qh_t;
struct iso_ep_t;
struct ep_info_t;
/*----------------------------------------------------------------------------------------*/
/* Periodic Frame List Size (256, 512, or 1024) */
/*----------------------------------------------------------------------------------------*/
#define FL_SIZE 1024 /* frame list size can be 256, 512, or 1024 */
#define NUM_IQH 11 /* depends on FL_SIZE, 256:9, 512:10, 1024:11 */
/*----------------------------------------------------------------------------------------*/
/* Interrupt Threshold Control (1, 2, 4, 6, .. 64) */
/*----------------------------------------------------------------------------------------*/
#define UCMDR_INT_THR_CTRL (0x1<<HSUSBH_UCMDR_ITC_Pos) /* 1 micro-frames */
/*----------------------------------------------------------------------------------------*/
/* Queue Element Transfer Descriptor (qTD) */
/*----------------------------------------------------------------------------------------*/
typedef struct qTD_t
{
uint32_t Next_qTD; /* Next qTD Pointer */
uint32_t Alt_Next_qTD; /* Alternate Next qTD Pointer */
uint32_t Token; /* qTD Token */
uint32_t Bptr[5]; /* qTD Buffer Page Pointer List */
/*
* The following members are used by USB Host libary.
*/
struct utr_t *utr; /* associated UTR */
uint32_t xfer_len; /* assigned transfer transfer length */
struct qh_t *qh; /* The QH that this qTD belong to. */
struct qTD_t *next; /* link for <qtd_list> of QH */
} qTD_T;
#define QTD_LIST_END 0x1 /* Indicate the terminate of qTD list. */
#define QTD_PTR(x) ((qTD_T *)((uint32_t)(x) & ~0x1F))
/*
* Status: qTD Token[7:0]
*/
#define QTD_STS_PS_OUT (0<<0) /* directs the HC to issue an OUT PID */
#define QTD_STS_PS_PING (1<<0) /* directs the HC to issue an PING PID */
#define QTD_STS_SPLIT_STRAT (0<<1) /* directs the HC to issue an Start split */
#define QTD_STS_SPLIT_COMPLETE (1<<1) /* directs the HC to issue an Complete split */
#define QTD_STS_MISS_MF (1<<2) /* miss a required complete-split transaction */
#define QTD_STS_XactErr (1<<3) /* Transaction Error occurred */
#define QTD_STS_BABBLE (1<<4) /* Babble Detected */
#define QTD_STS_DATA_BUFF_ERR (1<<5) /* Data Buffer Error */
#define QTD_STS_HALT (1<<6) /* Halted */
#define QTD_STS_ACTIVE (1<<7) /* Active */
/*
* PID: qTD Token[9:8]
*/
#define QTD_PID_Msk (0x3<<8)
#define QTD_PID_OUT (0<<8) /* generates token (E1H) */
#define QTD_PID_IN (1<<8) /* generates token (69H) */
#define QTD_PID_SETUP (2<<8) /* generates token (2DH) */
#define QTD_ERR_COUNTER (3<<10) /* Token[11:10] */
#define QTD_IOC (1<<15) /* Token[15] - Interrupt On Complete */
#define QTD_TODO_LEN_Pos 16 /* Token[31:16] - Total Bytes to Transfer */
#define QTD_TODO_LEN(x) (((x)>>16) & 0x7FFF)
#define QTD_DT (1UL<<31) /* Token[31] - Data Toggle */
/*----------------------------------------------------------------------------------------*/
/* Queue Head (QH) */
/*----------------------------------------------------------------------------------------*/
typedef struct qh_t
{
/* OHCI spec. Endpoint descriptor */
uint32_t HLink; /* Queue Head Horizontal Link Pointer */
uint32_t Chrst; /* Endpoint Characteristics: QH DWord 1 */
uint32_t Cap; /* Endpoint Capabilities: QH DWord 2 */
uint32_t Curr_qTD; /* Current qTD Pointer */
/*
* The followings are qTD Transfer Overlay
*/
uint32_t OL_Next_qTD; /* Next qTD Pointer */
uint32_t OL_Alt_Next_qTD; /* Alternate Next qTD Pointer */
uint32_t OL_Token; /* qTD Token */
uint32_t OL_Bptr[5]; /* qTD Buffer Page Pointer List */
/*
* The following members are used by USB Host libary.
*/
qTD_T *qtd_list; /* currently linked qTD transfers */
qTD_T *done_list; /* currently linked qTD transfers */
struct qh_t *next; /* point to the next QH in remove list */
} QH_T;
/* HLink[0] T field of "Queue Head Horizontal Link Pointer" */
#define QH_HLNK_END 0x1
/*
* HLink[2:1] Typ field of "Queue Head Horizontal Link Pointer"
*/
#define QH_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
#define QH_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
#define QH_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
#define QH_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
#define QH_PTR(x) ((QH_T *)((uint32_t)(x) & ~0x1F))
/*
* Bit fields of "Endpoint Characteristics"
*/
#define QH_NAK_RL (4L<<28) /* Chrst[31:28] - NAK Count Reload */
#define QH_CTRL_EP_FLAG (1<<27) /* Chrst[27] - Control Endpoint Flag */
#define QH_RCLM_LIST_HEAD (1<<15) /* Chrst[15] - Head of Reclamation List Flag */
#define QH_DTC (1<<14) /* Chrst[14] - Data Toggle Control */
#define QH_EPS_FULL (0<<12) /* Chrst[13:12] - Endpoint Speed (Full) */
#define QH_EPS_LOW (1<<12) /* Chrst[13:12] - Endpoint Speed (Low) */
#define QH_EPS_HIGH (2<<12) /* Chrst[13:12] - Endpoint Speed (High) */
#define QH_I_NEXT (1<<7) /* Chrst[7] - Inactivate on Next Transaction */
/*
* Bit fields of "Endpoint Capabilities"
*/
#define QH_MULT_Pos 30 /* Cap[31:30] - High-Bandwidth Pipe Multiplier */
#define QH_HUB_PORT_Pos 23 /* Cap[29:23] - Hub Port Number */
#define QH_HUB_ADDR_Pos 16 /* Cap[22:16] - Hub Addr */
#define QH_C_MASK_Msk 0xFF00 /* Cap[15:8] - uFrame C-mask */
#define QH_S_MASK_Msk 0x00FF /* Cap[7:0] - uFrame S-mask */
/*----------------------------------------------------------------------------------------*/
/* Isochronous (High-Speed) Transfer Descriptor (iTD) */
/*----------------------------------------------------------------------------------------*/
typedef struct itd_t
{
uint32_t Next_Link; /* Next Link Pointer */
uint32_t Transaction[8]; /* Transaction Status and Control */
uint32_t Bptr[7]; /* Buffer Page Pointer List */
/*
* The following members are used by USB Host libary.
*/
struct iso_ep_t *iso_ep; /* associated isochronous information block */
struct utr_t *utr; /* associated UTR */
uint32_t buff_base; /* buffer base address */
uint8_t fidx; /* iTD's first index to UTR iso frames */
uint8_t trans_mask; /* mask of activated transactions in iTD */
uint32_t sched_frnidx; /* scheduled frame index */
struct itd_t *next; /* used by software to maintain iTD list */
} iTD_T;
/*
* Next_Link[2:1] Typ field of "Next Schedule Element Pointer" Typ field
*/
#define ITD_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
#define ITD_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
#define ITD_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
#define ITD_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
#define ITD_PTR(x) ((iTD_T *)((uint32_t)(x) & ~0x1F))
/*
* Transaction[8]
*/
#define ITD_STATUS(x) (((x)>>28)&0xF)
#define ITD_STATUS_ACTIVE (0x80000000UL) /* Active */
#define ITD_STATUS_BUFF_ERR (0x40000000UL) /* Data Buffer Error */
#define ITD_STATUS_BABBLE (0x20000000UL) /* Babble Detected */
#define ITD_STATUS_XACT_ERR (0x10000000UL) /* Transcation Error */
#define ITD_XLEN_Pos 16
#define ITD_XFER_LEN(x) (((x)>>16)&0xFFF)
#define ITD_IOC (1<<15)
#define ITD_PG_Pos 12
#define ITD_XFER_OFF_Msk 0xFFF
/*
* Bptr[7]
*/
#define ITD_BUFF_PAGE_Pos 12
/* Bptr[0] */
#define ITD_EP_NUM_Pos 8
#define ITD_EP_NUM(itd) (((itd)->Bptr[0]>>8)&0xF)
#define ITD_DEV_ADDR_Pos 0
#define ITD_DEV_ADDR(itd) ((itd)->Bptr[0]&0x7F)
/* Bptr[1] */
#define ITD_DIR_IN (1<<11)
#define ITD_DIR_OUT (0<<11)
#define ITD_MAX_PKTSZ_Pos 0
#define ITD_MAX_PKTSZ(itd) ((itd)->Bptr[1]&0x7FF)
/*----------------------------------------------------------------------------------------*/
/* Split Isochronous (Full-Speed) Transfer Descriptor (siTD) */
/*----------------------------------------------------------------------------------------*/
typedef struct sitd_t
{
uint32_t Next_Link; /* Next Link Pointer */
uint32_t Chrst; /* Endpoint and Transaction Translator Characteristics */
uint32_t Sched; /* Micro-frame Schedule Control */
uint32_t StsCtrl; /* siTD Transfer Status and Control */
uint32_t Bptr[2]; /* Buffer Page Pointer List */
uint32_t BackLink; /* siTD Back Link Pointer */
/*
* The following members are used by USB Host libary.
*/
struct iso_ep_t *iso_ep; /* associated isochronous information block */
struct utr_t *utr; /* associated UTR */
uint8_t fidx; /* iTD's first index to UTR iso frames */
uint32_t sched_frnidx; /* scheduled frame index */
struct sitd_t *next; /* used by software to maintain siTD list */
} siTD_T;
#define SITD_LIST_END 0x1 /* Indicate the terminate of siTD list. */
#define SITD_XFER_IO_Msk (1UL<<31)
#define SITD_XFER_IN (1UL<<31)
#define SITD_XFER_OUT (0UL<<31)
#define SITD_PORT_NUM_Pos 24
#define SITD_HUB_ADDR_Pos 16
#define SITD_EP_NUM_Pos 8
#define SITD_DEV_ADDR_Pos 0
#define SITD_IOC (1UL<<31)
#define SITD_XFER_CNT_Pos 16
#define SITD_XFER_CNT_Msk (0x3FF<<SITD_XFER_CNT_Pos)
#define SITD_STATUS(x) ((x)&0xFC)
#define SITD_STATUS_ACTIVE 0x80
#define SITD_STATUS_ERR 0x40
#define SITD_STATUS_BUFF_ERR 0x20
#define SITD_BABBLE_DETECTED 0x10
#define SITD_STATUS_XFER_ERR 0x08
#define SITD_STATUS_MISSED_MF 0x04
#define SITD_STATUS_ERROR_MASK 0x78
/*
* Next_Link[2:1] Typ field of "Next Schedule Element Pointer" Typ field
*/
#define SITD_HLNK_ITD(x) (((uint32_t)(x) & ~0x1F) | 0x0)
#define SITD_HLNK_QH(x) (((uint32_t)(x) & ~0x1F) | 0x2)
#define SITD_HLNK_SITD(x) (((uint32_t)(x) & ~0x1F) | 0x4)
#define SITD_HLNK_FSTN(x) (((uint32_t)(x) & ~0x1F) | 0x6)
#define SITD_PTR(x) ((siTD_T *)((uint32_t)(x) & ~0x1F))
#define HLINK_IS_TERMINATED(x) (((uint32_t)(x) & 0x1) ? 1 : 0)
#define HLINK_IS_SITD(x) ((((uint32_t)(x) & 0x6) == 0x4) ? 1 : 0)
/*----------------------------------------------------------------------------------------*/
/* Isochronous endpoint transfer information block. (Software only) */
/*----------------------------------------------------------------------------------------*/
typedef struct iso_ep_t
{
struct ep_info_t *ep;
uint32_t next_frame; /* frame number of next scheduling */
iTD_T *itd_list; /* Reference to a list of installed iTDs */
iTD_T *itd_done_list; /* Reference to a list of completed iTDs */
siTD_T *sitd_list; /* Reference to a list of installed siTDs */
siTD_T *sitd_done_list; /* Reference to a list of completed siTDs */
struct iso_ep_t *next; /* used by software to maintain ISO EP list */
} ISO_EP_T;
extern void scan_isochronous_list(void);
/// @endcond
#endif /* _USBH_EHCI_H_ */

View File

@ -0,0 +1,124 @@
/**************************************************************************//**
* @file hub.h
* @version V1.00
* @brief USB Host hub class driver header file.
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef _USBH_HUB_H_
#define _USBH_HUB_H_
/// @cond HIDDEN_SYMBOLS
/*--------------------------------------------------------------------------*/
/* Hub class feature selectors (Table 11-17) */
/*--------------------------------------------------------------------------*/
#define FS_C_HUB_LOCAL_POWER 0
#define FS_C_HUB_OVER_CURRENT 1
#define FS_PORT_CONNECTION 0
#define FS_PORT_ENABLE 1
#define FS_PORT_SUSPEND 2
#define FS_PORT_OVER_CURRENT 3
#define FS_PORT_RESET 4
#define FS_PORT_POWER 8
#define FS_C_PORT_CONNECTION 16
#define FS_C_PORT_ENABLE 17
#define FS_C_PORT_SUSPEND 18
#define FS_C_PORT_OVER_CURRENT 19
#define FS_C_PORT_RESET 20
/*--------------------------------------------------------------------------*/
/* Hub/Port staus and change bits */
/*--------------------------------------------------------------------------*/
#define HUB_S_LOCAL_POWER (1UL << 0)
#define HUB_S_OVERCURRENT (1UL << 1)
#define HUB_C_LOCAL_POWER (1UL << 0)
#define HUB_C_OVERCURRENT (1UL << 1)
#define PORT_S_CONNECTION (1UL << 0)
#define PORT_S_ENABLE (1UL << 1)
#define PORT_S_SUSPEND (1UL << 2)
#define PORT_S_OVERCURRENT (1UL << 3)
#define PORT_S_RESET (1UL << 4)
#define PORT_S_PORT_POWER (1UL << 8)
#define PORT_S_LOW_SPEED (1UL << 9)
#define PORT_S_HIGH_SPEED (1UL << 10)
#define PORT_S_TEST (1UL << 11)
#define PORT_S_INDICATOR (1UL << 12)
#define PORT_C_CONNECTION (1UL << 0)
#define PORT_C_ENABLE (1UL << 1)
#define PORT_C_SUSPEND (1UL << 2)
#define PORT_C_OVERCURRENT (1UL << 3)
#define PORT_C_RESET (1UL << 4)
/*--------------------------------------------------------------------------*/
/* Hub descriptor */
/*--------------------------------------------------------------------------*/
typedef struct __attribute__((__packed__))
{
uint8_t bDescLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
uint16_t wHubCharacteristics;
uint8_t bPwrOn2PwrGood;
uint8_t bHubContrCurrent;
uint8_t bDeviceRemovble;
uint8_t PortPwrCtrlMask[16];
}
DESC_HUB_T;
/*
* wHubCharacteristics bit field mask
*/
#define HUB_CHAR_LPSM 0x0003 /* 00b: global port power, 01b: per port power, 1x: reserved */
#define HUB_CHAR_COMPOUND 0x0004 /* 1: is part of a compond device, 0: is not. */
#define HUB_CHAR_OCPM 0x0018 /* 00b: global over-current protection, 01b: per port, 1x: reserved */
#define HUB_CHAR_TTTT 0x0060 /* TT think time. 00b: 8FS, 01b: 16FS, 10b: 24FS, 11b: 32FS */
#define HUB_CHAR_PORTIND 0x0080 /* 1: port indicator (LED) supported, 0: not */
/* port indicator status selectors */
#define HUB_LED_AUTO 0
#define HUB_LED_AMBER 1
#define HUB_LED_GREEN 2
#define HUB_LED_OFF 3
/*--------------------------------------------------------------------------*/
/* Port reset retry and time-out settings */
/*--------------------------------------------------------------------------*/
#define HUB_DEBOUNCE_TIME 800 /* Hub connect/disconnect de-bounce time in ms */
#define PORT_RESET_RETRY 3 /* port reset retry times */
#define PORT_RESET_TIME_MS 50 /* port reset time (ms) */
#define PORT_RESET_RETRY_INC_MS 250 /* increased reset time (ms) after reset failed */
#define HUB_STATUS_MAX_BYTE 2 /* maximum number of interrupt-in status bytes */
/* 2 can support up to 16 port hubs */
/* 4 can support up to 32 port hubs */
/* Note!! If modeifed to 4, "uint16_t sc_bitmap" */
/* MUST be changed as "uint32_t sc_bitmap" */
typedef struct hub_dev_t
{
IFACE_T *iface; /*!< Interface device of this hub \hideinitializer */
UTR_T *utr; /*!< Interrupt in UTR of this hub \hideinitializer */
// uint8_t buff[HUB_STATUS_MAX_BYTE]; /*!< Interrupt in buffer \hideinitializer */
uint16_t sc_bitmap; /*!< Hub and Port Status Change Bitmap \hideinitializer */
uint8_t bNbrPorts; /*!< Number of ports \hideinitializer */
uint8_t bPwrOn2PwrGood; /*!< Hub power on to power good time \hideinitializer */
char pos_id[MAX_HUB_DEVICE + 1]; /*!< Hub position identifier \hideinitializer */
int (*port_reset)(struct hub_dev_t *hub, int port); /*!< Port reset function \hideinitializer */
UDEV_T *children; /*!< Child device list. \hideinitializer */
} HUB_DEV_T;
/// @endcond
#endif /* _USBH_HUB_H_ */

View File

@ -0,0 +1,147 @@
/**************************************************************************//**
* @file ohci.h
* @version V1.00
* @brief USB OHCI host controller driver header file.
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef _USBH_OHCI_H_
#define _USBH_OHCI_H_
/// @cond HIDDEN_SYMBOLS
struct utr_t;
struct udev_t;
/* OHCI CONTROL AND STATUS REGISTER MASKS */
/*
* Host controller functional state.
* for HCFS(HcControl[7:6])
*/
#define HCFS_RESET (0UL << USBH_HcControl_HCFS_Pos)
#define HCFS_RESUME (1UL << USBH_HcControl_HCFS_Pos)
#define HCFS_OPER (2UL << USBH_HcControl_HCFS_Pos)
#define HCFS_SUSPEND (3UL << USBH_HcControl_HCFS_Pos)
/*----------------------------------------------------------------------------------------*/
/* Endpoint descriptor */
/*----------------------------------------------------------------------------------------*/
typedef struct ed_t
{
/* OHCI spec. Endpoint descriptor */
uint32_t Info;
uint32_t TailP;
uint32_t HeadP;
uint32_t NextED;
/* The following members are used by USB Host libary. */
uint8_t bInterval;
uint16_t next_sf; /* for isochronous transfer, recording the next SF */
struct ed_t *next; /* point to the next ED in remove list */
} ED_T;
#define ED_CTRL_FA_Pos 0 /* Info[6:0] - Function address */
#define ED_CTRL_EN_Pos 7 /* Info[10:7] - Endpoint number */
#define ED_CTRL_DIR_Pos 11 /* Info[12:11] - Direction */
#define ED_CTRL_MPS_Pos 16 /* Info[26:16] - Maximum packet size */
#define ED_FUNC_ADDR_Msk (0x7f)
#define ED_EP_ADDR_Msk (0xf<<7)
#define ED_DIR_Msk (0x3<<11)
#define ED_SPEED_Msk (1<<13)
#define ED_MAX_PK_SIZE_Msk (0x7ff<<16)
#define ED_DIR_BY_TD (0<<ED_CTRL_DIR_Pos)
#define ED_DIR_OUT (1<<ED_CTRL_DIR_Pos)
#define ED_DIR_IN (2<<ED_CTRL_DIR_Pos)
#define ED_SPEED_FULL (0<<13) /* Info[13] - 0: is full speed device */
#define ED_SPEED_LOW (1<<13) /* Info[13] - 1: is low speed device */
#define ED_SKIP (1<<14) /* Info[14] - 1: HC skip this ED */
#define ED_FORMAT_GENERAL (0<<15) /* Info[15] - 0: is a general TD */
#define ED_FORMAT_ISO (1<<15) /* Info[15] - 1: is an isochronous TD */
#define ED_HEADP_HALT (1<<0) /* HeadP[0] - 1: Halt; 0: Not */
/*----------------------------------------------------------------------------------------*/
/* Transfer descriptor */
/*----------------------------------------------------------------------------------------*/
/* general transfer descriptor */
typedef struct td_t
{
uint32_t Info;
uint32_t CBP; /* Current Buffer Pointer */
uint32_t NextTD; /* Next TD */
uint32_t BE; /* Buffer End */
uint32_t PSW[4]; /* PSW 0~7 */
/* The following members are used by USB Host libary. */
uint32_t buff_start; /* Buffer Start */
ED_T *ed; /* The ED that this TD belong to. */
struct utr_t *utr; /* associated UTR */
struct td_t *next; /* point to next TD of the same UTR */
} TD_T;
#define TD_ADDR_MASK 0xFFFFFFFC
/* Completion codes */
enum OCHI_CC_CODE
{
/* mapping of the OHCI CC status to error codes */
CC_NOERROR, /* No Error */
CC_CRC, /* CRC Error */
CC_BITSTUFF, /* Bit Stuff */
CC_DATA_TOGGLE, /* Data Toggle */
CC_STALL, /* Stall */
CC_NOTRESPONSE, /* DevNotResp */
CC_PID_CHECK, /* PIDCheck */
CC_UNEXPECTED_PID, /* UnExpPID */
CC_DATA_OVERRUN, /* DataOver */
CC_DATA_UNDERRUN, /* DataUnder */
CC_RESERVED1, /* reserved */
CC_RESERVED2, /* reserved */
CC_BUFFER_OVERRUN, /* BufferOver */
CC_BUFFER_UNDERRUN, /* BuffUnder */
CC_NOT_ACCESS /* Not Access */
};
/* TD control field */
#define TD_CC 0xF0000000
#define TD_CC_GET(td) ((td >>28) & 0x0F)
#define TD_CC_SET(td, cc) (td) = ((td) & 0x0FFFFFFF) | (((cc) & 0x0F) << 28)
#define TD_T_DATA0 0x02000000
#define TD_T_DATA1 0x03000000
#define TD_R 0x00040000
#define TD_DP 0x00180000
#define TD_DP_IN 0x00100000
#define TD_DP_OUT 0x00080000
#define MAXPSW 8
/* steel TD reserved bits to keep driver data */
#define TD_TYPE_Msk (0x3<<16)
#define TD_TYPE_CTRL (0x0<<16)
#define TD_TYPE_BULK (0x1<<16)
#define TD_TYPE_INT (0x2<<16)
#define TD_TYPE_ISO (0x3<<16)
#define TD_CTRL_Msk (0x7<<15)
#define TD_CTRL_DATA (1<<15)
/*
* The HCCA (Host Controller Communications Area) is a 256 byte
* structure defined in the OHCI spec. that the host controller is
* told the base address of. It must be 256-byte aligned.
*/
typedef struct
{
uint32_t int_table[32]; /* Interrupt ED table */
uint16_t frame_no; /* current frame number */
uint16_t pad1; /* set to 0 on each frame_no change */
uint32_t done_head; /* info returned for an interrupt */
uint8_t reserved_for_hc[116];
} HCCA_T;
/// @endcond
#endif /* _USBH_OHCI_H_ */

View File

@ -0,0 +1,394 @@
/**************************************************************************//**
* @file usb.h
* @version V1.00
* @brief USB Host library header file.
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef _USBH_H_
#define _USBH_H_
#include "config.h"
#include "usbh_lib.h"
#include "ehci.h"
#include "ohci.h"
/// @cond HIDDEN_SYMBOLS
struct utr_t;
struct udev_t;
struct hub_dev_t;
struct iface_t;
struct ep_info_t;
/*----------------------------------------------------------------------------------*/
/* USB device request setup packet */
/*----------------------------------------------------------------------------------*/
typedef struct __attribute__((__packed__))
{
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
}
DEV_REQ_T;
/*
* bmRequestType[7] - Data transfer direction
*/
#define REQ_TYPE_OUT 0x00
#define REQ_TYPE_IN 0x80
/*
* bmRequestType[6:5] - Type
*/
#define REQ_TYPE_STD_DEV 0x00
#define REQ_TYPE_CLASS_DEV 0x20
#define REQ_TYPE_VENDOR_DEV 0x40
/*
* bmRequestType[4:0] - Recipient
*/
#define REQ_TYPE_TO_DEV 0x00
#define REQ_TYPE_TO_IFACE 0x01
#define REQ_TYPE_TO_EP 0x02
#define REQ_TYPE_TO_OTHER 0x03
/*
* Standard Requests
*/
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_SET_INTERFACE 0x0B
/*
* Descriptor Types
*/
#define USB_DT_STANDARD 0x00
#define USB_DT_CLASS 0x20
#define USB_DT_VENDOR 0x40
#define USB_DT_DEVICE 0x01
#define USB_DT_CONFIGURATION 0x02
#define USB_DT_STRING 0x03
#define USB_DT_INTERFACE 0x04
#define USB_DT_ENDPOINT 0x05
#define USB_DT_DEVICE_QUALIFIER 0x06
#define USB_DT_OTHER_SPEED_CONF 0x07
#define USB_DT_IFACE_POWER 0x08
/*----------------------------------------------------------------------------------*/
/* USB standard descriptors */
/*----------------------------------------------------------------------------------*/
/* Descriptor header */
typedef struct __attribute__((__packed__))
{
uint8_t bLength;
uint8_t bDescriptorType;
}
DESC_HDR_T;
/*----------------------------------------------------------------------------------*/
/* USB device descriptor */
/*----------------------------------------------------------------------------------*/
typedef struct __attribute__((__packed__)) /*!< device descriptor structure */
{
uint8_t bLength; /*!< Length of device descriptor */
uint8_t bDescriptorType; /*!< Device descriptor type */
uint16_t bcdUSB; /*!< USB version number */
uint8_t bDeviceClass; /*!< Device class code */
uint8_t bDeviceSubClass; /*!< Device subclass code */
uint8_t bDeviceProtocol; /*!< Device protocol code */
uint8_t bMaxPacketSize0; /*!< Maximum packet size of control endpoint*/
uint16_t idVendor; /*!< Vendor ID */
uint16_t idProduct; /*!< Product ID */
uint16_t bcdDevice; /*!< Device ID */
uint8_t iManufacturer; /*!< Manufacture description string ID */
uint8_t iProduct; /*!< Product description string ID */
uint8_t iSerialNumber; /*!< Serial number description string ID */
uint8_t bNumConfigurations; /*!< Total number of configurations */
}
DESC_DEV_T; /*!< device descriptor structure */
/*
* Configuration Descriptor
*/
typedef struct __attribute__((__packed__)) usb_config_descriptor /*!< Configuration descriptor structure */
{
uint8_t bLength; /*!< Length of configuration descriptor */
uint8_t bDescriptorType; /*!< Descriptor type */
uint16_t wTotalLength; /*!< Total length of this configuration */
uint8_t bNumInterfaces; /*!< Total number of interfaces */
uint8_t bConfigurationValue; /*!< Configuration descriptor number */
uint8_t iConfiguration; /*!< String descriptor ID */
uint8_t bmAttributes; /*!< Configuration characteristics */
uint8_t MaxPower; /*!< Maximum power consumption */
} DESC_CONF_T; /*!< Configuration descriptor structure */
/*
* Interface Descriptor
*/
typedef struct __attribute__((__packed__))usb_interface_descriptor /*!< Interface descriptor structure */
{
uint8_t bLength; /*!< Length of interface descriptor */
uint8_t bDescriptorType; /*!< Descriptor type */
uint8_t bInterfaceNumber; /*!< Interface number */
uint8_t bAlternateSetting; /*!< Alternate setting number */
uint8_t bNumEndpoints; /*!< Number of endpoints */
uint8_t bInterfaceClass; /*!< Interface class code */
uint8_t bInterfaceSubClass; /*!< Interface subclass code */
uint8_t bInterfaceProtocol; /*!< Interface protocol code */
uint8_t iInterface; /*!< Interface ID */
} DESC_IF_T; /*!< Interface descriptor structure */
/*
* Endpoint Descriptor
*/
typedef struct __attribute__((__packed__)) usb_endpoint_descriptor /*!< Endpoint descriptor structure */
{
uint8_t bLength; /*!< Length of endpoint descriptor */
uint8_t bDescriptorType; /*!< Descriptor type */
uint8_t bEndpointAddress; /*!< Endpoint address */
uint8_t bmAttributes; /*!< Endpoint attribute */
uint16_t wMaxPacketSize; /*!< Maximum packet size */
uint8_t bInterval; /*!< Synchronous transfer interval */
uint8_t bRefresh; /*!< Refresh */
uint8_t bSynchAddress; /*!< Sync address */
} DESC_EP_T; /*!< Endpoint descriptor structure */
/*
* Endpoint descriptor bEndpointAddress[7] - direction
*/
#define EP_ADDR_DIR_MASK 0x80
#define EP_ADDR_DIR_IN 0x80
#define EP_ADDR_DIR_OUT 0x00
/*
* Endpoint descriptor bmAttributes[1:0] - transfer type
*/
#define EP_ATTR_TT_MASK 0x03
#define EP_ATTR_TT_CTRL 0x00
#define EP_ATTR_TT_ISO 0x01
#define EP_ATTR_TT_BULK 0x02
#define EP_ATTR_TT_INT 0x03
/*----------------------------------------------------------------------------------*/
/* USB Host controller driver */
/*----------------------------------------------------------------------------------*/
typedef struct
{
int (*init)(void);
void (*shutdown)(void);
void (*suspend)(void);
void (*resume)(void);
int (*ctrl_xfer)(struct utr_t *utr);
int (*bulk_xfer)(struct utr_t *utr);
int (*int_xfer)(struct utr_t *utr);
int (*iso_xfer)(struct utr_t *utr);
int (*quit_xfer)(struct utr_t *utr, struct ep_info_t *ep);
/* root hub support */
int (*rthub_port_reset)(int port);
int (*rthub_polling)(void);
} HC_DRV_T;
/*----------------------------------------------------------------------------------*/
/* USB device driver */
/*----------------------------------------------------------------------------------*/
typedef struct
{
int (*probe)(struct iface_t *iface);
void (*disconnect)(struct iface_t *iface);
void (*suspend)(struct iface_t *iface);
void (*resume)(struct iface_t *iface);
} UDEV_DRV_T;
/*----------------------------------------------------------------------------------*/
/* USB device */
/*----------------------------------------------------------------------------------*/
typedef enum
{
SPEED_LOW,
SPEED_FULL,
SPEED_HIGH
} SPEED_E;
typedef struct ep_info_t
{
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint8_t bInterval;
uint8_t bToggle;
uint16_t wMaxPacketSize;
void *hw_pipe; /*!< point to the HC assocaied endpoint \hideinitializer */
} EP_INFO_T;
typedef struct udev_t
{
DESC_DEV_T descriptor; /*!< Device descriptor. \hideinitializer */
struct hub_dev_t *parent; /*!< parent hub device \hideinitializer */
uint8_t port_num; /*!< The hub port this device connected on \hideinitializer */
uint8_t dev_num; /*!< device number \hideinitializer */
int8_t cur_conf; /*!< Currentll selected configuration \hideinitializer */
SPEED_E speed; /*!< device speed (low/full/high) \hideinitializer */
/*
* The followings are lightweight USB stack internal used .
*/
uint8_t *cfd_buff; /*!< Configuration descriptor buffer. \hideinitializer */
EP_INFO_T ep0; /*!< Endpoint 0 \hideinitializer */
HC_DRV_T *hc_driver; /*!< host controller driver \hideinitializer */
struct iface_t *iface_list; /*!< Working interface list \hideinitializer */
struct udev_t *next; /*!< link for global usb device list \hideinitializer */
} UDEV_T;
typedef struct alt_iface_t
{
DESC_IF_T *ifd; /*!< point to the location of this alternative interface descriptor in UDEV_T->cfd_buff */
EP_INFO_T ep[MAX_EP_PER_IFACE]; /*!< endpoints of this alternative interface */
} ALT_IFACE_T;
typedef struct iface_t
{
UDEV_T *udev; /*!< USB device \hideinitializer */
uint8_t if_num; /*!< Interface number \hideinitializer */
uint8_t num_alt; /*!< Number of alternative interface \hideinitializer */
ALT_IFACE_T *aif; /*!< Point to the active alternative interface */
ALT_IFACE_T alt[MAX_ALT_PER_IFACE]; /*!< List of alternative interface \hideinitializer */
UDEV_DRV_T *driver; /*!< Interface associated driver \hideinitializer */
void *context; /*!< Reference to device context \hideinitializer */
struct iface_t *next; /*!< Point to next interface of the same device. Started from UDEV_T->iface_list \hideinitializer */
} IFACE_T;
/*----------------------------------------------------------------------------------*/
/* URB (USB Request Block) */
/*----------------------------------------------------------------------------------*/
#define IF_PER_UTR 8 /* number of frames per UTR isochronous transfer (DO NOT modify it!) */
typedef void (*FUNC_UTR_T)(struct utr_t *);
typedef struct utr_t
{
UDEV_T *udev; /*!< point to associated USB device \hideinitializer */
DEV_REQ_T setup; /*!< buffer for setup packet \hideinitializer */
EP_INFO_T *ep; /*!< associated endpoint \hideinitializer */
uint8_t *buff; /*!< transfer buffer \hideinitializer */
uint8_t bIsTransferDone; /*!< tansfer done? \hideinitializer */
uint32_t data_len; /*!< length of data to be transferred \hideinitializer */
uint32_t xfer_len; /*!< length of transferred data \hideinitializer */
uint8_t bIsoNewSched; /*!< New schedule isochronous transfer \hideinitializer */
uint16_t iso_sf; /*!< Isochronous start frame number \hideinitializer */
uint16_t iso_xlen[IF_PER_UTR]; /*!< transfer length of isochronous frames \hideinitializer */
uint8_t *iso_buff[IF_PER_UTR]; /*!< transfer buffer address of isochronous frames \hideinitializer */
int iso_status[IF_PER_UTR]; /*!< transfer status of isochronous frames \hideinitializer */
int td_cnt; /*!< number of transfer descriptors \hideinitializer */
int status; /*!< return status \hideinitializer */
int interval; /*!< interrupt/isochronous interval \hideinitializer */
void *context; /*!< point to deivce proprietary data area \hideinitializer */
FUNC_UTR_T func; /*!< tansfer done call-back function \hideinitializer */
struct utr_t *next; /* point to the next UTR of the same endpoint. \hideinitializer */
} UTR_T;
/*----------------------------------------------------------------------------------*/
/* Global variables */
/*----------------------------------------------------------------------------------*/
extern USBH_T *_ohci;
extern HSUSBH_T *_ehci;
extern HC_DRV_T ohci_driver;
extern HC_DRV_T ehci_driver;
extern UDEV_T *g_udev_list;
extern volatile int _IsInUsbInterrupt;
/*----------------------------------------------------------------------------------*/
/* USB stack exported functions */
/*----------------------------------------------------------------------------------*/
extern void usbh_delay_ms(int msec);
extern void dump_ohci_regs(void);
extern void dump_ohci_ports(void);
extern void dump_ohci_int_table(void);
extern void dump_ehci_regs(void);
extern void dump_ehci_qtd(qTD_T *qtd);
extern void dump_ehci_asynclist(void);
extern void dump_ehci_period_frame_list_simple(void);
extern void usbh_dump_buff_bytes(uint8_t *buff, int nSize);
extern void usbh_dump_interface_descriptor(DESC_IF_T *if_desc);
extern void usbh_dump_endpoint_descriptor(DESC_EP_T *ep_desc);
extern void usbh_dump_iface(IFACE_T *iface);
extern void usbh_dump_ep_info(EP_INFO_T *ep);
/*
* Memory management functions
*/
extern void USB_InitializeMemoryPool(void);
extern void *USB_malloc(int wanted_size, int boundary);
extern void USB_free(void *);
extern int USB_available_memory(void);
extern int USB_allocated_memory(void);
extern void usbh_memory_init(void);
extern uint32_t usbh_memory_used(void);
extern void *usbh_alloc_mem(int size);
extern void usbh_free_mem(void *p, int size);
extern int alloc_dev_address(void);
extern void free_dev_address(int dev_addr);
extern UDEV_T *alloc_device(void);
extern void free_device(UDEV_T *udev);
extern UTR_T *alloc_utr(UDEV_T *udev);
extern void free_utr(UTR_T *utr);
extern ED_T *alloc_ohci_ED(void);
extern void free_ohci_ED(ED_T *ed);
extern TD_T *alloc_ohci_TD(UTR_T *utr);
extern void free_ohci_TD(TD_T *td);
extern QH_T *alloc_ehci_QH(void);
extern void free_ehci_QH(QH_T *qh);
extern qTD_T *alloc_ehci_qTD(UTR_T *utr);
extern void free_ehci_qTD(qTD_T *qtd);
extern iTD_T *alloc_ehci_iTD(void);
extern void free_ehci_iTD(iTD_T *itd);
extern siTD_T *alloc_ehci_siTD(void);
extern void free_ehci_siTD(siTD_T *sitd);
extern void usbh_hub_init(void);
extern int usbh_connect_device(UDEV_T *);
extern void usbh_disconnect_device(UDEV_T *);
extern int usbh_register_driver(UDEV_DRV_T *driver);
extern EP_INFO_T *usbh_iface_find_ep(IFACE_T *iface, uint8_t ep_addr, uint8_t dir_type);
extern int usbh_reset_device(UDEV_T *);
extern int usbh_reset_port(UDEV_T *);
/*
* USB Standard Request functions
*/
extern int usbh_get_device_descriptor(UDEV_T *udev, DESC_DEV_T *desc_buff);
extern int usbh_get_config_descriptor(UDEV_T *udev, uint8_t *desc_buff, int buff_len);
extern int usbh_set_configuration(UDEV_T *udev, uint8_t conf_val);
extern int usbh_set_interface(IFACE_T *iface, uint16_t alt_setting);
extern int usbh_clear_halt(UDEV_T *udev, uint16_t ep_addr);
extern int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout);
extern int usbh_bulk_xfer(UTR_T *utr);
extern int usbh_int_xfer(UTR_T *utr);
extern int usbh_iso_xfer(UTR_T *utr);
extern int usbh_quit_utr(UTR_T *utr);
extern int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep);
/// @endcond HIDDEN_SYMBOLS
#endif /* _USBH_H_ */

View File

@ -0,0 +1,188 @@
/**************************************************************************//**
* @file usbh_lib.h
* @version V1.10
* $Revision: 4 $
* $Date: 15/06/10 2:06p $
* @brief USB Host library exported header file.
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
******************************************************************************/
#ifndef _USBH_LIB_H_
#define _USBH_LIB_H_
#include "nuc980.h"
#ifdef __cplusplus
extern "C"
{
#endif
/** @addtogroup Library Library
@{
*/
/** @addtogroup USBH_Library USB Host Library
@{
*/
/** @addtogroup USBH_EXPORTED_CONSTANTS USB Host Exported Constants
@{
*/
#define USBH_OK 0 /*!< No error. */
#define USBH_ERR_MEMORY_OUT -10 /*!< Out of memory. */
#define USBH_ERR_IF_ALT_LIMIT -11 /*!< Number of alternative interface > MAX_ALT_PER_IFACE */
#define USBH_ERR_IF_EP_LIMIT -15 /*!< Number of endpoints > MAX_EP_PER_IFACE */
#define USBH_ERR_NOT_SUPPORTED -101 /*!< Device/Class/Transfer not supported */
#define USBH_ERR_NOT_MATCHED -103 /*!< Not macthed */
#define USBH_ERR_NOT_EXPECTED -104 /*!< Unknown or unexpected */
#define USBH_ERR_INVALID_PARAM -105 /*!< Invalid parameter */
#define USBH_ERR_NOT_FOUND -106 /*!< Device or interface not found */
#define USBH_ERR_EP_NOT_FOUND -107 /*!< Endpoint not found */
#define USBH_ERR_DESCRIPTOR -137 /*!< Failed to parse USB descriptors */
#define USBH_ERR_SET_DEV_ADDR -139 /*!< Failed to set device address */
#define USBH_ERR_SET_CONFIG -151 /*!< Failed to set device configuration */
#define USBH_ERR_TRANSFER -201 /*!< USB transfer error */
#define USBH_ERR_TIMEOUT -203 /*!< USB transfer time-out */
#define USBH_ERR_ABORT -205 /*!< USB transfer aborted due to disconnect or reset */
#define USBH_ERR_PORT_RESET -255 /*!< Hub port reset failed */
#define USBH_ERR_SCH_OVERRUN -257 /*!< USB isochronous schedule overrun */
#define USBH_ERR_DISCONNECTED -259 /*!< USB device was disconnected */
#define USBH_ERR_TRANSACTION -271 /*!< USB transaction timeout, CRC, Bad PID, etc. */
#define USBH_ERR_BABBLE_DETECTED -272 /*!< A ¡§babble¡¨ is detected during the transaction */
#define USBH_ERR_DATA_BUFF -274 /*!< Data buffer overrun or underrun */
#define USBH_ERR_CC_NO_ERR -280 /*!< OHCI CC code - no error */
#define USBH_ERR_CRC -281 /*!< USB trasfer CRC error */
#define USBH_ERR_BIT_STUFF -282 /*!< USB transfer bit stuffing error */
#define USBH_ERR_DATA_TOGGLE -283 /*!< USB trasfer data toggle error */
#define USBH_ERR_STALL -284 /*!< USB trasfer STALL error */
#define USBH_ERR_DEV_NO_RESP -285 /*!< USB trasfer device no response error */
#define USBH_ERR_PID_CHECK -286 /*!< USB trasfer PID check failure */
#define USBH_ERR_UNEXPECT_PID -287 /*!< USB trasfer unexpected PID error */
#define USBH_ERR_DATA_OVERRUN -288 /*!< USB trasfer data overrun error */
#define USBH_ERR_DATA_UNDERRUN -289 /*!< USB trasfer data underrun error */
#define USBH_ERR_BUFF_OVERRUN -292 /*!< USB trasfer buffer overrun error */
#define USBH_ERR_BUFF_UNDERRUN -293 /*!< USB trasfer buffer underrun error */
#define USBH_ERR_NOT_ACCESS0 -294 /*!< USB trasfer not accessed error */
#define USBH_ERR_NOT_ACCESS1 -295 /*!< USB trasfer not accessed error */
#define USBH_ERR_OHCI_INIT -301 /*!< Failed to initialize OHIC controller. */
#define USBH_ERR_OHCI_EP_BUSY -303 /*!< The endpoint is under transfer. */
#define USBH_ERR_EHCI_INIT -501 /*!< Failed to initialize EHCI controller. */
#define USBH_ERR_EHCI_QH_BUSY -503 /*!< the Queue Head is busy. */
#define UMAS_OK 0 /*!< No error. */
#define UMAS_ERR_NO_DEVICE -1031 /*!< No Mass Stroage Device found. */
#define UMAS_ERR_IO -1033 /*!< Device read/write failed. */
#define UMAS_ERR_INIT_DEVICE -1035 /*!< failed to init MSC device */
#define UMAS_ERR_CMD_STATUS -1037 /*!< SCSI command status failed */
#define UMAS_ERR_IVALID_PARM -1038 /*!< Invalid parameter. */
#define UMAS_ERR_DRIVE_NOT_FOUND -1039 /*!< drive not found */
#define HID_RET_OK 0 /*!< Return with no errors. */
#define HID_RET_DEV_NOT_FOUND -1081 /*!< HID device not found or removed. */
#define HID_RET_IO_ERR -1082 /*!< USB transfer failed. */
#define HID_RET_INVALID_PARAMETER -1083 /*!< Invalid parameter. */
#define HID_RET_OUT_OF_MEMORY -1084 /*!< Out of memory. */
#define HID_RET_NOT_SUPPORTED -1085 /*!< Function not supported. */
#define HID_RET_EP_NOT_FOUND -1086 /*!< Endpoint not found. */
#define HID_RET_PARSING -1087 /*!< Failed to parse HID descriptor */
#define HID_RET_XFER_IS_RUNNING -1089 /*!< The transfer has been enabled. */
#define HID_RET_REPORT_NOT_FOUND -1090 /*!< The transfer has been enabled. */
#define UAC_RET_OK 0 /*!< Return with no errors. */
#define UAC_RET_DEV_NOT_FOUND -2001 /*!< Audio Class device not found or removed. */
#define UAC_RET_FUNC_NOT_FOUND -2002 /*!< Audio device has no this function. */
#define UAC_RET_IO_ERR -2003 /*!< USB transfer failed. */
#define UAC_RET_DATA_LEN -2004 /*!< Unexpected transfer length */
#define UAC_RET_INVALID -2005 /*!< Invalid parameter or usage. */
#define UAC_RET_OUT_OF_MEMORY -2007 /*!< Out of memory. */
#define UAC_RET_DRV_NOT_SUPPORTED -2009 /*!< Function not supported by this UAC driver. */
#define UAC_RET_DEV_NOT_SUPPORTED -2011 /*!< Function not supported by the UAC device. */
#define UAC_RET_PARSER -2013 /*!< Failed to parse UAC descriptor */
#define UAC_RET_IS_STREAMING -2015 /*!< Audio pipe is on streaming. */
/*@}*/ /* end of group USBH_EXPORTED_CONSTANTS */
/** @addtogroup USBH_EXPORTED_TYPEDEF USB Host Typedef
@{
*/
struct udev_t;
typedef void (CONN_FUNC)(struct udev_t *udev, int param);
struct line_coding_t;
struct cdc_dev_t;
typedef void (CDC_CB_FUNC)(struct cdc_dev_t *cdev, uint8_t *rdata, int data_len);
struct usbhid_dev;
typedef void (HID_IR_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *rdata, uint32_t data_len); /*!< interrupt in callback function \hideinitializer */
typedef void (HID_IW_FUNC)(struct usbhid_dev *hdev, uint16_t ep_addr, int status, uint8_t *wbuff, uint32_t *data_len); /*!< interrupt out callback function \hideinitializer */
struct uac_dev_t;
typedef int (UAC_CB_FUNC)(struct uac_dev_t *dev, uint8_t *data, int len); /*!< audio in callback function \hideinitializer */
/*@}*/ /* end of group USBH_EXPORTED_STRUCT */
/** @addtogroup USBH_EXPORTED_FUNCTIONS USB Host Exported Functions
@{
*/
/*------------------------------------------------------------------*/
/* */
/* USB Core Library APIs */
/* */
/*------------------------------------------------------------------*/
extern void usbh_core_init(void);
extern int usbh_polling_root_hubs(void);
extern void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func);
extern void usbh_suspend(void);
extern void usbh_resume(void);
extern struct udev_t *usbh_find_device(char *hub_id, int port);
/**
* @brief A function return current tick count.
* @return Current tick.
* @details User application must provide this function to return current tick.
* The tick should increase by 1 for every 10 ms.
*/
extern uint32_t usbh_get_ticks(void); /* This function must be provided by user application. */
extern uint32_t usbh_tick_from_millisecond(uint32_t msec); /* This function must be provided by user application. */
/// @cond HIDDEN_SYMBOLS
extern void dump_ohci_regs(void);
extern void dump_ehci_regs(void);
extern void dump_ohci_ports(void);
extern void dump_ehci_ports(void);
extern uint32_t usbh_memory_used(void);
/// @endcond HIDDEN_SYMBOLS
/*@}*/ /* end of group USBH_EXPORTED_FUNCTIONS */
/*@}*/ /* end of group USBH_Library */
/*@}*/ /* end of group LIBRARY */
#ifdef __cplusplus
}
#endif
#endif /* _USBH_LIB_H_ */
/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,918 @@
/**************************************************************************//**
* @file ehci_iso.c
* @version V1.10
* $Revision: 11 $
* $Date: 14/10/03 1:54p $
* @brief USB EHCI isochornous transfer driver.
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nuc980.h"
#include "usb.h"
#include "hub.h"
/// @cond HIDDEN_SYMBOLS
uint32_t g_flr_cnt; /* frame list rollover counter */
ISO_EP_T *iso_ep_list; /* list of activated isochronous pipes */
extern uint32_t *_PFList; /* Periodic frame list */
static const uint16_t sitd_OUT_Smask [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f };
static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep);
/*
* Inspect the iTD can be reclaimed or not. If yes, collect the transaction results.
* Return: 1 - reclaimed
* 0 - not completed
*/
static int review_itd(iTD_T *itd)
{
UTR_T *utr;
uint32_t frnidx = itd->sched_frnidx;
uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
int i, fidx;
// printf("R - %d %d, 0x%x\n", now_frame, frnidx, itd->Transaction[0]);
if (now_frame == frnidx)
{
for (i = 0; i < 8; i++)
{
if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
return 0; /* have any not completed frames */
}
}
else if (now_frame > frnidx)
{
if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
return 0; /* don't touch it */
}
else
{
if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
return 0; /* don't touch it */
}
/*
* Reclaim this iTD
*/
utr = itd->utr;
fidx = itd->fidx;
for (i = 0; i < 8; i++)
{
if (!(itd->trans_mask & (0x1 << i)))
continue; /* not scheduled micro-frame */
if (ITD_STATUS(itd->Transaction[i]))
{
if (itd->Transaction[i] & ITD_STATUS_ACTIVE)
{
utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
utr->status = USBH_ERR_NOT_ACCESS0;
}
else if (itd->Transaction[i] & ITD_STATUS_BABBLE)
{
utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
utr->status = USBH_ERR_TRANSFER;
}
else if (itd->Transaction[i] & ITD_STATUS_BUFF_ERR)
{
utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
utr->status = USBH_ERR_TRANSFER;
}
else
{
utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
utr->status = USBH_ERR_TRANSFER;
}
}
else
{
utr->iso_status[fidx] = 0;
utr->iso_xlen[fidx] = ITD_XFER_LEN(itd->Transaction[i]);
}
fidx++;
}
utr->td_cnt--;
if (utr->td_cnt == 0) /* All iTD of this UTR done */
{
utr->bIsTransferDone = 1;
if (utr->func)
utr->func(utr);
}
return 1; /* to be reclaimed */
}
/*
* Inspect the siTD can be reclaimed or not. If yes, collect the transaction results.
* Return: 1 - reclaimed
* 0 - not completed
*/
static int review_sitd(siTD_T *sitd)
{
UTR_T *utr;
uint32_t frnidx = sitd->sched_frnidx;
uint32_t now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
int fidx;
uint32_t TotalBytesToTransfer;
if (now_frame == frnidx)
{
if (SITD_STATUS(sitd->StsCtrl) == SITD_STATUS_ACTIVE)
return 0;
}
else if (now_frame > frnidx)
{
if ((now_frame - frnidx) > EHCI_ISO_RCLM_RANGE)
return 0; /* don't touch it */
}
else
{
if (now_frame + FL_SIZE - frnidx > EHCI_ISO_RCLM_RANGE)
return 0; /* don't touch it */
}
/*
* Reclaim this siTD
*/
utr = sitd->utr;
fidx = sitd->fidx;
if (SITD_STATUS(sitd->StsCtrl))
{
if (sitd->StsCtrl & SITD_STATUS_ACTIVE)
{
utr->iso_status[fidx] = USBH_ERR_NOT_ACCESS0;
}
else if (sitd->StsCtrl & SITD_BABBLE_DETECTED)
{
utr->iso_status[fidx] = USBH_ERR_BABBLE_DETECTED;
utr->status = USBH_ERR_TRANSFER;
}
else if (sitd->StsCtrl & SITD_STATUS_BUFF_ERR)
{
utr->iso_status[fidx] = USBH_ERR_DATA_BUFF;
utr->status = USBH_ERR_TRANSFER;
}
else
{
utr->iso_status[fidx] = USBH_ERR_TRANSACTION;
utr->status = USBH_ERR_TRANSFER;
}
}
else
{
TotalBytesToTransfer = (sitd->StsCtrl & SITD_XFER_CNT_Msk) >> SITD_XFER_CNT_Pos;
utr->iso_xlen[fidx] = utr->iso_xlen[fidx] - TotalBytesToTransfer;
utr->iso_status[fidx] = 0;
}
utr->td_cnt--;
if (utr->td_cnt == 0) /* All iTD of this UTR done */
{
utr->bIsTransferDone = 1;
if (utr->func)
utr->func(utr);
}
return 1; /* to be reclaimed */
}
/*
* Some iTD/siTD may be scheduled but not serviced due to time missed.
* This function scan several earlier frames and drop unserviced iTD/siTD if found.
*/
void scan_isochronous_list(void)
{
ISO_EP_T *iso_ep = iso_ep_list;
iTD_T *itd, *itd_pre, *p;
siTD_T *sitd, *sitd_pre, *sp;
uint32_t frnidx;
DISABLE_EHCI_IRQ();
while (iso_ep != NULL) /* Search all activated iso endpoints */
{
/*--------------------------------------------------------------------------------*/
/* Scan all iTDs */
/*--------------------------------------------------------------------------------*/
itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
itd_pre = NULL;
while (itd != NULL) /* traverse all iTDs of itd list */
{
if (review_itd(itd)) /* inspect and reclaim iTD */
{
/*------------------------------------------------------------------------*/
/* Remove this iTD from period frame list */
/*------------------------------------------------------------------------*/
frnidx = itd->sched_frnidx;
if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
{
/* is the first entry, just change to next */
_PFList[frnidx] = itd->Next_Link;
}
else
{
p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
{
p = ITD_PTR(p->Next_Link);
}
if (p == NULL) /* link list out of control! */
{
USB_error("An iTD lost refernece to periodic frame list! 0x%x -> %d\n", (int)itd, frnidx);
}
else /* remove iTD from list */
{
p->Next_Link = itd->Next_Link;
}
}
/*------------------------------------------------------------------------*/
/* Remove this iTD from iso_ep's iTD list */
/*------------------------------------------------------------------------*/
if (itd_pre == NULL)
{
iso_ep->itd_list = itd->next;
}
else
{
itd_pre->next = itd->next;
}
p = itd->next;
free_ehci_iTD(itd);
itd = p;
}
else
{
itd_pre = itd;
itd = itd->next; /* traverse to the next iTD of iTD list */
}
}
/*--------------------------------------------------------------------------------*/
/* Scan all siTDs */
/*--------------------------------------------------------------------------------*/
sitd = iso_ep->sitd_list; /* get the first siTD from iso_ep's siTD list */
sitd_pre = NULL;
while (sitd != NULL) /* traverse all siTDs of sitd list */
{
if (review_sitd(sitd)) /* inspect and reclaim siTD */
{
/*------------------------------------------------------------------------*/
/* Remove this siTD from period frame list */
/*------------------------------------------------------------------------*/
frnidx = sitd->sched_frnidx;
if (_PFList[frnidx] == SITD_HLNK_SITD(sitd))
{
/* is the first entry, just change to next */
_PFList[frnidx] = sitd->Next_Link;
}
else
{
sp = SITD_PTR(_PFList[frnidx]); /* find the preceding siTD */
while ((SITD_PTR(sp->Next_Link) != sitd) && (sp != NULL))
{
sp = SITD_PTR(sp->Next_Link);
}
if (sp == NULL) /* link list out of control! */
{
USB_error("An siTD lost reference to periodic frame list! 0x%x -> %d\n", (int)sitd, frnidx);
}
else /* remove iTD from list */
{
sp->Next_Link = sitd->Next_Link;
}
}
/*------------------------------------------------------------------------*/
/* Remove this siTD from iso_ep's siTD list */
/*------------------------------------------------------------------------*/
if (sitd_pre == NULL)
{
iso_ep->sitd_list = sitd->next;
}
else
{
sitd_pre->next = sitd->next;
}
sp = sitd->next;
free_ehci_siTD(sitd);
sitd = sp;
}
else
{
sitd_pre = sitd;
sitd = sitd->next; /* traverse to the next siTD of siTD list */
}
}
iso_ep = iso_ep->next;
}
ENABLE_EHCI_IRQ();
}
static void write_itd_info(UTR_T *utr, iTD_T *itd)
{
UDEV_T *udev = utr->udev;
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
uint32_t buff_page_addr;
int i;
buff_page_addr = itd->buff_base & 0xFFFFF000; /* 4K page */
for (i = 0; i < 7; i++)
{
itd->Bptr[i] = buff_page_addr + (0x1000 * i);
}
/* EndPtr R Device Address */
itd->Bptr[0] |= (udev->dev_num) | ((ep->bEndpointAddress & 0xF) << ITD_EP_NUM_Pos);
itd->Bptr[1] |= ep->wMaxPacketSize; /* Maximum Packet Size */
if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
itd->Bptr[1] |= ITD_DIR_IN;
else
itd->Bptr[1] |= ITD_DIR_OUT;
itd->Bptr[2] |= (ep->wMaxPacketSize + 1023) / 1024; /* Mult */
}
static void write_itd_micro_frame(UTR_T *utr, int fidx, iTD_T *itd, int mf)
{
uint32_t buff_addr;
buff_addr = (uint32_t)(utr->iso_buff[fidx]); /* xfer buffer start address of this frame */
itd->Transaction[mf] = ITD_STATUS_ACTIVE | /* Status */
((utr->iso_xlen[fidx] & 0xFFF) << ITD_XLEN_Pos) | /* Transaction Length */
((buff_addr & 0xFFFFF000) - (itd->buff_base & 0xFFFFF000)) | /* PG */
(buff_addr & 0xFFF); /* Transaction offset */
}
static void remove_iso_ep_from_list(ISO_EP_T *iso_ep)
{
ISO_EP_T *p;
if (iso_ep_list == iso_ep)
{
iso_ep_list = iso_ep->next; /* it's the first entry, remove it */
return;
}
p = iso_ep_list; /* find the previous entry of iso_ep */
while (p->next != NULL)
{
if (p->next == iso_ep)
{
break;
}
p = p->next;
}
if (p->next == NULL)
{
return; /* not found */
}
p->next = iso_ep->next; /* remove iso_ep from list */
}
static __inline void add_itd_to_iso_ep(ISO_EP_T *iso_ep, iTD_T *itd)
{
iTD_T *p;
itd->next = NULL;
if (iso_ep->itd_list == NULL)
{
iso_ep->itd_list = itd;
return;
}
/*
* Find the tail entry of iso_ep->itd_list
*/
p = iso_ep->itd_list;
while (p->next != NULL)
{
p = p->next;
}
p->next = itd;
}
int ehci_iso_xfer(UTR_T *utr)
{
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
ISO_EP_T *iso_ep; /* software iso endpoint descriptor */
iTD_T *itd, *itd_next, *itd_list = NULL;
int i, itd_cnt;
int trans_mask; /* bit mask of used xfer in an iTD */
int fidx; /* index to the 8 iso frames of UTR */
int interval; /* frame interval of iTD */
if (ep->hw_pipe != NULL)
{
iso_ep = (ISO_EP_T *)ep->hw_pipe; /* get reference of the isochronous endpoint */
if (utr->bIsoNewSched)
iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
}
else
{
/* first time transfer of this iso endpoint */
iso_ep = usbh_alloc_mem(sizeof(*iso_ep));
if (iso_ep == NULL)
return USBH_ERR_MEMORY_OUT;
memset(iso_ep, 0, sizeof(*iso_ep));
iso_ep->ep = ep;
iso_ep->next_frame = (((_ehci->UFINDR + (EHCI_ISO_DELAY * 8)) & HSUSBH_UFINDR_FI_Msk) >> 3) & 0x3FF;
ep->hw_pipe = iso_ep;
/*
* Add this iso_ep into iso_ep_list
*/
DISABLE_EHCI_IRQ();
iso_ep->next = iso_ep_list;
iso_ep_list = iso_ep;
ENABLE_EHCI_IRQ();
}
if (utr->udev->speed == SPEED_FULL)
return ehci_iso_split_xfer(utr, iso_ep);
/*------------------------------------------------------------------------------------*/
/* Allocate iTDs */
/*------------------------------------------------------------------------------------*/
if (ep->bInterval < 2) /* transfer interval is 1 micro-frame */
{
trans_mask = 0xFF;
itd_cnt = 1; /* required 1 iTD for one UTR */
interval = 1; /* iTD frame interval of this endpoint */
}
else if (ep->bInterval < 4) /* transfer interval is 2 micro-frames */
{
trans_mask = 0x55;
itd_cnt = 2; /* required 2 iTDs for one UTR */
interval = 1; /* iTD frame interval of this endpoint */
}
else if (ep->bInterval < 8) /* transfer interval is 4 micro-frames */
{
trans_mask = 0x44;
itd_cnt = 4; /* required 4 iTDs for one UTR */
interval = 1; /* iTD frame interval of this endpoint */
}
else if (ep->bInterval < 16) /* transfer interval is 8 micro-frames */
{
trans_mask = 0x08; /* there's 1 transfer in one iTD */
itd_cnt = 8; /* required 8 iTDs for one UTR */
interval = 1; /* iTD frame interval of this endpoint */
}
else if (ep->bInterval < 32) /* transfer interval is 16 micro-frames */
{
trans_mask = 0x10; /* there's 1 transfer in one iTD */
itd_cnt = 8; /* required 8 iTDs for one UTR */
interval = 2; /* iTD frame interval of this endpoint */
}
else if (ep->bInterval < 64) /* transfer interval is 32 micro-frames */
{
trans_mask = 0x02; /* there's 1 transfer in one iTD */
itd_cnt = 8; /* required 8 iTDs for one UTR */
interval = 4; /* iTD frame interval of this endpoint */
}
else /* transfer interval is 64 micro-frames */
{
trans_mask = 0x04; /* there's 1 transfer in one iTD */
itd_cnt = 8; /* required 8 iTDs for one UTR */
interval = 8; /* iTD frame interval of this endpoint */
}
for (i = 0; i < itd_cnt; i++) /* allocate all iTDs required by UTR */
{
itd = alloc_ehci_iTD();
if (itd == NULL)
goto malloc_failed;
if (itd_list == NULL) /* link all iTDs */
{
itd_list = itd;
}
else
{
itd->next = itd_list;
itd_list = itd;
}
}
utr->td_cnt = itd_cnt;
/*------------------------------------------------------------------------------------*/
/* Fill and link all iTDs */
/*------------------------------------------------------------------------------------*/
utr->iso_sf = iso_ep->next_frame;
fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
for (itd = itd_list; (itd != NULL);)
{
if (fidx >= IF_PER_UTR) /* unlikely */
{
USB_error("EHCI driver ITD bug!?\n");
goto malloc_failed;
}
itd->utr = utr;
itd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
itd->buff_base = (uint32_t)(utr->iso_buff[fidx]); /* iTD buffer base is buffer of the first UTR iso frame serviced by this iTD */
itd->trans_mask = trans_mask;
write_itd_info(utr, itd);
for (i = 0; i < 8; i++) /* settle xfer into micro-frames */
{
if (!(trans_mask & (0x1 << i)))
{
itd->Transaction[i] = 0; /* not accesed */
continue; /* not scheduled micro-frame */
}
write_itd_micro_frame(utr, fidx, itd, i);
fidx++; /* preceed to next UTR iso frame */
if (fidx == IF_PER_UTR) /* is the last scheduled micro-frame? */
{
/* raise interrupt on completed */
itd->Transaction[i] |= ITD_IOC;
break;
}
}
itd_next = itd->next; /* remember the next itd */
// USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
/*
* Link iTD to period frame list
*/
DISABLE_EHCI_IRQ();
itd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
add_itd_to_iso_ep(iso_ep, itd); /* add to software itd list */
itd->Next_Link = _PFList[itd->sched_frnidx]; /* keep the next link */
_PFList[itd->sched_frnidx] = ITD_HLNK_ITD(itd);
iso_ep->next_frame = (iso_ep->next_frame + interval) % FL_SIZE;
ENABLE_EHCI_IRQ();
itd = itd_next;
}
_ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
return 0;
malloc_failed:
while (itd_list != NULL)
{
itd = itd_list;
itd_list = itd->next;
free_ehci_iTD(itd);
}
return USBH_ERR_MEMORY_OUT;
}
static __inline void add_sitd_to_iso_ep(ISO_EP_T *iso_ep, siTD_T *sitd)
{
siTD_T *p;
sitd->next = NULL;
if (iso_ep->sitd_list == NULL)
{
iso_ep->sitd_list = sitd;
return;
}
/*
* Find the tail entry of iso_ep->itd_list
*/
p = iso_ep->sitd_list;
while (p->next != NULL)
{
p = p->next;
}
p->next = sitd;
}
static void write_sitd_info(UTR_T *utr, siTD_T *sitd)
{
UDEV_T *udev = utr->udev;
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
uint32_t buff_page_addr;
int xlen = utr->iso_xlen[sitd->fidx];
int scnt;
sitd->Chrst = (udev->port_num << SITD_PORT_NUM_Pos) |
(udev->parent->iface->udev->dev_num << SITD_HUB_ADDR_Pos) |
((ep->bEndpointAddress & 0xF) << SITD_EP_NUM_Pos) |
(udev->dev_num << SITD_DEV_ADDR_Pos);
buff_page_addr = ((uint32_t)utr->iso_buff[sitd->fidx]) & 0xFFFFF000;
sitd->Bptr[0] = (uint32_t)(utr->iso_buff[sitd->fidx]);
sitd->Bptr[1] = buff_page_addr + 0x1000;
scnt = (xlen + 187) / 188;
if ((ep->bEndpointAddress & EP_ADDR_DIR_MASK) == EP_ADDR_DIR_IN) /* I/O */
{
sitd->Chrst |= SITD_XFER_IN;
sitd->Sched = (1 << (scnt + 2)) - 1;
sitd->Sched = (sitd->Sched << 10) | 0x1;
//sitd->Sched <<= 1;
}
else
{
sitd->Chrst |= SITD_XFER_OUT;
sitd->Sched = sitd_OUT_Smask[scnt - 1];
if (scnt > 1)
{
sitd->Bptr[1] |= (0x1 << 3); /* Transaction position (TP) 01b: Begin */
}
sitd->Bptr[1] |= scnt; /* Transaction count (T-Count) */
}
if (sitd->fidx == IF_PER_UTR)
{
sitd->Sched |= SITD_IOC;
}
sitd->StsCtrl = (xlen << SITD_XFER_CNT_Pos) | SITD_STATUS_ACTIVE;
sitd->BackLink = SITD_LIST_END;
}
static void ehci_sitd_adjust_schedule(siTD_T *sitd)
{
siTD_T *hlink = (siTD_T *)_PFList[sitd->sched_frnidx];
uint32_t uframe_mask = 0x00;
while (hlink && !HLINK_IS_TERMINATED(hlink) && HLINK_IS_SITD(hlink))
{
hlink = SITD_PTR(hlink);
if (hlink != sitd)
{
if ((hlink->Chrst & SITD_XFER_IO_Msk) == SITD_XFER_IN)
{
uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by IN S-mask */
uframe_mask |= ((hlink->Sched >> 8) & 0xFF); /* mark micro-frames used by IN C-mask */
}
else
{
uframe_mask |= (hlink->Sched & 0xFF); /* mark micro-frames used by OUT S-mask */
}
}
hlink = SITD_PTR(hlink->Next_Link);
}
uframe_mask = uframe_mask | (uframe_mask << 8); /* mark both S-mask and C-mask */
if (uframe_mask)
{
/*
* Shift afterward one micro-frame until no conflicts.
*/
while (1)
{
if (sitd->Sched & uframe_mask)
{
sitd->Sched = (sitd->Sched & 0xFFFF0000) | ((sitd->Sched << 1) & 0xFFFF);
}
else
{
break; /* no conflit, done. */
}
}
}
}
static int ehci_iso_split_xfer(UTR_T *utr, ISO_EP_T *iso_ep)
{
EP_INFO_T *ep = utr->ep; /* reference to isochronous endpoint */
siTD_T *sitd, *sitd_next, *sitd_list = NULL;
int i;
int fidx; /* index to the 8 iso frames of UTR */
if (utr->udev->parent == NULL)
{
USB_error("siso xfer - parent lost!\n");
return USBH_ERR_INVALID_PARAM;
}
/*------------------------------------------------------------------------------------*/
/* Allocate siTDs */
/*------------------------------------------------------------------------------------*/
for (i = 0; i < IF_PER_UTR; i++) /* allocate all siTDs required by UTR */
{
sitd = alloc_ehci_siTD();
if (sitd == NULL)
goto malloc_failed;
if (sitd_list == NULL) /* link all siTDs */
{
sitd_list = sitd;
}
else
{
sitd->next = sitd_list;
sitd_list = sitd;
}
}
utr->td_cnt = IF_PER_UTR;
/*------------------------------------------------------------------------------------*/
/* Fill and link all siTDs */
/*------------------------------------------------------------------------------------*/
utr->iso_sf = iso_ep->next_frame;
fidx = 0; /* index to UTR iso frmes (total IF_PER_UTR) */
for (sitd = sitd_list; (sitd != NULL); fidx++)
{
if (fidx >= IF_PER_UTR) /* unlikely */
{
USB_error("EHCI driver siTD bug!?\n");
goto malloc_failed;
}
sitd->utr = utr;
sitd->fidx = fidx; /* index to UTR's n'th IF_PER_UTR frame */
write_sitd_info(utr, sitd);
sitd_next = sitd->next; /* remember the next itd */
// USB_debug("Link iTD 0x%x, %d\n", (int)itd, iso_ep->next_frame);
/*
* Link iTD to period frame list
*/
sitd->sched_frnidx = iso_ep->next_frame; /* remember it for reclamation scan */
DISABLE_EHCI_IRQ();
ehci_sitd_adjust_schedule(sitd);
add_sitd_to_iso_ep(iso_ep, sitd); /* add to software itd list */
sitd->Next_Link = _PFList[sitd->sched_frnidx];/* keep the next link */
_PFList[sitd->sched_frnidx] = SITD_HLNK_SITD(sitd);
iso_ep->next_frame = (iso_ep->next_frame + ep->bInterval) % FL_SIZE;
ENABLE_EHCI_IRQ();
sitd = sitd_next;
}
_ehci->UCMDR |= HSUSBH_UCMDR_PSEN_Msk; /* periodic list enable */
return 0;
malloc_failed:
while (sitd_list != NULL)
{
sitd = sitd_list;
sitd_list = sitd->next;
free_ehci_siTD(sitd);
}
return USBH_ERR_MEMORY_OUT;
}
/*
* If it's an isochronous endpoint, quit current transfer via UTR or hardware EP.
*/
int ehci_quit_iso_xfer(UTR_T *utr, EP_INFO_T *ep)
{
ISO_EP_T *iso_ep;
iTD_T *itd, *itd_next, *p;
uint32_t frnidx;
uint32_t now_frame;
if (ep == NULL)
{
if (utr == NULL)
return USBH_ERR_NOT_FOUND;
if (utr->ep == NULL)
return USBH_ERR_NOT_FOUND;
ep = utr->ep;
}
if ((ep->bmAttributes & EP_ATTR_TT_MASK) != EP_ATTR_TT_ISO)
return USBH_ERR_NOT_FOUND; /* not isochronous endpoint */
/*------------------------------------------------------------------------------------*/
/* It's an iso endpoint. Remove it as required. */
/*------------------------------------------------------------------------------------*/
iso_ep = iso_ep_list;
while (iso_ep != NULL) /* Search all activated iso endpoints */
{
if (iso_ep->ep == ep)
break;
iso_ep = iso_ep->next;
}
if (iso_ep == NULL)
return 0; /* should have been removed */
itd = iso_ep->itd_list; /* get the first iTD from iso_ep's iTD list */
while (itd != NULL) /* traverse all iTDs of itd list */
{
itd_next = itd->next; /* remember the next iTD */
utr = itd->utr;
/*--------------------------------------------------------------------------------*/
/* Remove this iTD from period frame list */
/*--------------------------------------------------------------------------------*/
frnidx = itd->sched_frnidx;
/*
* Prevent to race with Host Controller. If the iTD to be removed is located in
* current or next frame, wait until HC passed through it.
*/
while (1)
{
now_frame = (_ehci->UFINDR >> 3) & 0x3FF;
if ((now_frame == frnidx) || (((now_frame + 1) % 1024) == frnidx))
continue;
break;
}
if (_PFList[frnidx] == ITD_HLNK_ITD(itd))
{
/* is the first entry, just change to next */
_PFList[frnidx] = itd->Next_Link;
}
else
{
p = ITD_PTR(_PFList[frnidx]); /* find the preceding iTD */
while ((ITD_PTR(p->Next_Link) != itd) && (p != NULL))
{
p = ITD_PTR(p->Next_Link);
}
if (p == NULL) /* link list out of control! */
{
USB_error("ehci_quit_iso_xfer - An iTD lost reference to periodic frame list! 0x%x on %d\n", (int)itd, frnidx);
}
else /* remove iTD from list */
{
p->Next_Link = itd->Next_Link;
}
}
utr->td_cnt--;
if (utr->td_cnt == 0) /* All iTD of this UTR done */
{
utr->bIsTransferDone = 1;
if (utr->func)
utr->func(utr);
utr->status = USBH_ERR_ABORT;
}
free_ehci_iTD(itd);
itd = itd_next;
}
/*
* Remove iso_ep from iso_ep_list
*/
remove_iso_ep_from_list(iso_ep);
usbh_free_mem(iso_ep, sizeof(*iso_ep)); /* free this iso_ep */
ep->hw_pipe = NULL;
if (iso_ep_list == NULL)
_ehci->UCMDR &= ~HSUSBH_UCMDR_PSEN_Msk;
return 0;
}
/// @endcond HIDDEN_SYMBOLS
/*** (C) COPYRIGHT 2017 Nuvoton Technology Corp. ***/

View File

@ -0,0 +1,540 @@
/**************************************************************************//**
* @file mem_alloc.c
* @version V1.10
* $Revision: 11 $
* $Date: 14/10/03 1:54p $
* @brief USB host library memory allocation functions.
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usb.h"
/// @cond HIDDEN_SYMBOLS
//#define MEM_DEBUG
#ifdef MEM_DEBUG
#define mem_debug rt_kprintf
#else
#define mem_debug(...)
#endif
#ifdef __ICCARM__
#pragma data_alignment=1024
uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE];
#else
uint8_t _mem_pool_buff[MEM_POOL_UNIT_NUM][MEM_POOL_UNIT_SIZE] __attribute__((aligned(1024)));
#endif
static uint8_t *_mem_pool[MEM_POOL_UNIT_NUM];
static uint8_t _unit_used[MEM_POOL_UNIT_NUM];
static volatile int _usbh_mem_used;
static volatile int _usbh_max_mem_used;
static volatile int _mem_pool_used;
UDEV_T *g_udev_list;
uint8_t _dev_addr_pool[128];
static volatile int _device_addr;
static int _sidx = 0;;
/*--------------------------------------------------------------------------*/
/* Memory alloc/free recording */
/*--------------------------------------------------------------------------*/
void usbh_memory_init(void)
{
int i;
if (sizeof(TD_T) > MEM_POOL_UNIT_SIZE)
{
USB_error("TD_T - MEM_POOL_UNIT_SIZE too small!\n");
while (1);
}
if (sizeof(ED_T) > MEM_POOL_UNIT_SIZE)
{
USB_error("ED_T - MEM_POOL_UNIT_SIZE too small!\n");
while (1);
}
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
_unit_used[i] = 0;
_mem_pool[i] = (uint8_t *)((uint32_t)&_mem_pool_buff[i] | NON_CACHE_MASK);
}
_usbh_mem_used = 0L;
_usbh_max_mem_used = 0L;
_mem_pool_used = 0;
_sidx = 0;
g_udev_list = NULL;
memset(_dev_addr_pool, 0, sizeof(_dev_addr_pool));
_device_addr = 1;
USB_InitializeMemoryPool();
}
uint32_t usbh_memory_used(void)
{
mem_debug("USB static memory: %d/%d, heap used: %d\n", _mem_pool_used, MEM_POOL_UNIT_NUM, _usbh_mem_used);
return _usbh_mem_used;
}
static void memory_counter(int size)
{
_usbh_mem_used += size;
if (_usbh_mem_used > _usbh_max_mem_used)
_usbh_max_mem_used = _usbh_mem_used;
}
void *usbh_alloc_mem(int size)
{
void *p;
p = USB_malloc(size, 16);
if (p == NULL)
{
USB_error("usbh_alloc_mem failed! %d\n", size);
return NULL;
}
memset(p, 0, size);
memory_counter(size);
return p;
}
void usbh_free_mem(void *p, int size)
{
USB_free(p);
memory_counter(0 - size);
}
/*--------------------------------------------------------------------------*/
/* USB device allocate/free */
/*--------------------------------------------------------------------------*/
UDEV_T *alloc_device(void)
{
UDEV_T *udev;
udev = (UDEV_T *)USB_malloc(sizeof(*udev), 16);
if (udev == NULL)
{
USB_error("alloc_device failed!\n");
return NULL;
}
memset(udev, 0, sizeof(*udev));
memory_counter(sizeof(*udev));
udev->cur_conf = -1; /* must! used to identify the first SET CONFIGURATION */
udev->next = g_udev_list; /* chain to global device list */
g_udev_list = udev;
return udev;
}
void free_device(UDEV_T *udev)
{
UDEV_T *d;
if (udev == NULL)
return;
if (udev->cfd_buff != NULL)
usbh_free_mem(udev->cfd_buff, MAX_DESC_BUFF_SIZE);
/*
* Remove it from the global device list
*/
if (g_udev_list == udev)
{
g_udev_list = g_udev_list->next;
}
else
{
d = g_udev_list;
while (d != NULL)
{
if (d->next == udev)
{
d->next = udev->next;
break;
}
d = d->next;
}
}
USB_free(udev);
memory_counter(-sizeof(*udev));
}
int alloc_dev_address(void)
{
_device_addr++;
if (_device_addr >= 128)
_device_addr = 1;
while (1)
{
if (_dev_addr_pool[_device_addr] == 0)
{
_dev_addr_pool[_device_addr] = 1;
return _device_addr;
}
_device_addr++;
if (_device_addr >= 128)
_device_addr = 1;
}
}
void free_dev_address(int dev_addr)
{
if (dev_addr < 128)
_dev_addr_pool[dev_addr] = 0;
}
/*--------------------------------------------------------------------------*/
/* UTR (USB Transfer Request) allocate/free */
/*--------------------------------------------------------------------------*/
UTR_T *alloc_utr(UDEV_T *udev)
{
#if 0
UTR_T *utr, *utr_noncache;
utr = (UTR_T *)USB_malloc(sizeof(*utr), 16);
if (utr == NULL)
{
USB_error("alloc_utr failed!\n");
return NULL;
}
utr_noncache = (UTR_T *)((uint32_t)utr | NONCACHEABLE);
memory_counter(sizeof(*utr));
memset(utr_noncache, 0, sizeof(*utr));
utr_noncache->udev = udev;
mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache);
return utr_noncache;
#else
UTR_T *utr;
utr = (UTR_T *)USB_malloc(sizeof(*utr), 16);
if (utr == NULL)
{
USB_error("alloc_utr failed!\n");
return NULL;
}
memory_counter(sizeof(*utr));
memset(utr, 0, sizeof(*utr));
utr->udev = udev;
mem_debug("[ALLOC] [UTR] - 0x%x\n", (int)utr_noncache);
return utr;
#endif
}
void free_utr(UTR_T *utr)
{
if (utr == NULL)
return;
mem_debug("[FREE] [UTR] - 0x%x\n", (int)utr);
#if 0
if ((uint32_t)utr & NONCACHEABLE)
utr = (UTR_T *)((uint32_t)utr & ~NONCACHEABLE);
#endif
USB_free(utr);
memory_counter(0 - (int)sizeof(*utr));
}
/*--------------------------------------------------------------------------*/
/* OHCI ED allocate/free */
/*--------------------------------------------------------------------------*/
ED_T *alloc_ohci_ED(void)
{
int i;
ED_T *ed;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if (_unit_used[i] == 0)
{
_unit_used[i] = 1;
_mem_pool_used++;
ed = (ED_T *)_mem_pool[i];
memset(ed, 0, sizeof(*ed));
mem_debug("[ALLOC] [ED] - 0x%x\n", (int)ed);
return ed;
}
}
USB_error("alloc_ohci_ED failed!\n");
return NULL;
}
void free_ohci_ED(ED_T *ed)
{
int i;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)ed)
{
mem_debug("[FREE] [ED] - 0x%x\n", (int)ed);
_unit_used[i] = 0;
_mem_pool_used--;
return;
}
}
USB_debug("free_ohci_ED - not found! (ignored in case of multiple UTR)\n");
}
/*--------------------------------------------------------------------------*/
/* OHCI TD allocate/free */
/*--------------------------------------------------------------------------*/
TD_T *alloc_ohci_TD(UTR_T *utr)
{
int i;
TD_T *td;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if (_unit_used[i] == 0)
{
_unit_used[i] = 1;
_mem_pool_used++;
td = (TD_T *)_mem_pool[i];
memset(td, 0, sizeof(*td));
td->utr = utr;
mem_debug("[ALLOC] [TD] - 0x%x\n", (int)td);
return td;
}
}
USB_error("alloc_ohci_TD failed!\n");
return NULL;
}
void free_ohci_TD(TD_T *td)
{
int i;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)td)
{
mem_debug("[FREE] [TD] - 0x%x\n", (int)td);
_unit_used[i] = 0;
_mem_pool_used--;
return;
}
}
USB_error("free_ohci_TD - not found!\n");
}
/*--------------------------------------------------------------------------*/
/* EHCI QH allocate/free */
/*--------------------------------------------------------------------------*/
QH_T *alloc_ehci_QH(void)
{
int i;
QH_T *qh = NULL;
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
{
if (_unit_used[i] == 0)
{
_unit_used[i] = 1;
_sidx = i;
_mem_pool_used++;
qh = (QH_T *)_mem_pool[i];
memset(qh, 0, sizeof(*qh));
mem_debug("[ALLOC] [QH] - 0x%x\n", (int)qh);
break;
}
}
if (qh == NULL)
{
USB_error("alloc_ehci_QH failed!\n");
return NULL;
}
qh->Curr_qTD = QTD_LIST_END;
qh->OL_Next_qTD = QTD_LIST_END;
qh->OL_Alt_Next_qTD = QTD_LIST_END;
qh->OL_Token = QTD_STS_HALT;
return qh;
}
void free_ehci_QH(QH_T *qh)
{
int i;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)qh)
{
mem_debug("[FREE] [QH] - 0x%x\n", (int)qh);
_unit_used[i] = 0;
_mem_pool_used--;
return;
}
}
USB_debug("free_ehci_QH - not found! (ignored in case of multiple UTR)\n");
}
/*--------------------------------------------------------------------------*/
/* EHCI qTD allocate/free */
/*--------------------------------------------------------------------------*/
qTD_T *alloc_ehci_qTD(UTR_T *utr)
{
int i;
qTD_T *qtd;
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
{
if (_unit_used[i] == 0)
{
_unit_used[i] = 1;
_sidx = i;
_mem_pool_used++;
qtd = (qTD_T *)_mem_pool[i];
memset(qtd, 0, sizeof(*qtd));
qtd->Next_qTD = QTD_LIST_END;
qtd->Alt_Next_qTD = QTD_LIST_END;
qtd->Token = 0x1197B7F; // QTD_STS_HALT; visit_qtd() will not remove a qTD with this mark. It means the qTD still not ready for transfer.
qtd->utr = utr;
mem_debug("[ALLOC] [qTD] - 0x%x\n", (int)qtd);
return qtd;
}
}
USB_error("alloc_ehci_qTD failed!\n");
return NULL;
}
void free_ehci_qTD(qTD_T *qtd)
{
int i;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)qtd)
{
mem_debug("[FREE] [qTD] - 0x%x\n", (int)qtd);
_unit_used[i] = 0;
_mem_pool_used--;
return;
}
}
USB_error("free_ehci_qTD 0x%x - not found!\n", (int)qtd);
}
/*--------------------------------------------------------------------------*/
/* EHCI iTD allocate/free */
/*--------------------------------------------------------------------------*/
iTD_T *alloc_ehci_iTD(void)
{
int i;
iTD_T *itd;
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
{
if (i + 2 >= MEM_POOL_UNIT_NUM)
continue;
if ((_unit_used[i] == 0) && (_unit_used[i + 1] == 0))
{
_unit_used[i] = _unit_used[i + 1] = 1;
_sidx = i + 1;
_mem_pool_used += 2;
itd = (iTD_T *)_mem_pool[i];
memset(itd, 0, sizeof(*itd));
mem_debug("[ALLOC] [iTD] - 0x%x\n", (int)itd);
return itd;
}
}
USB_error("alloc_ehci_iTD failed!\n");
return NULL;
}
void free_ehci_iTD(iTD_T *itd)
{
int i;
for (i = 0; i + 1 < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)itd)
{
mem_debug("[FREE] [iTD] - 0x%x\n", (int)itd);
_unit_used[i] = _unit_used[i + 1] = 0;
_mem_pool_used -= 2;
return;
}
}
USB_error("free_ehci_iTD 0x%x - not found!\n", (int)itd);
}
/*--------------------------------------------------------------------------*/
/* EHCI iTD allocate/free */
/*--------------------------------------------------------------------------*/
siTD_T *alloc_ehci_siTD(void)
{
int i;
siTD_T *sitd;
for (i = (_sidx + 1) % MEM_POOL_UNIT_NUM; i != _sidx; i = (i + 1) % MEM_POOL_UNIT_NUM)
{
if (_unit_used[i] == 0)
{
_unit_used[i] = 1;
_sidx = i;
_mem_pool_used ++;
sitd = (siTD_T *)_mem_pool[i];
memset(sitd, 0, sizeof(*sitd));
mem_debug("[ALLOC] [siTD] - 0x%x\n", (int)sitd);
return sitd;
}
}
USB_error("alloc_ehci_siTD failed!\n");
return NULL;
}
void free_ehci_siTD(siTD_T *sitd)
{
int i;
for (i = 0; i < MEM_POOL_UNIT_NUM; i++)
{
if ((uint32_t)_mem_pool[i] == (uint32_t)sitd)
{
mem_debug("[FREE] [siTD] - 0x%x\n", (int)sitd);
_unit_used[i] = 0;
_mem_pool_used--;
return;
}
}
USB_error("free_ehci_siTD 0x%x - not found!\n", (int)sitd);
}
/// @endcond HIDDEN_SYMBOLS
/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,324 @@
/**************************************************************************//**
* @file support.c
* @version V1.10
* $Revision: 11 $
* $Date: 14/10/03 1:54p $
* @brief Functions to support USB host driver.
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usb.h"
/// @cond HIDDEN_SYMBOLS
#define USB_MEMORY_POOL_SIZE (32*1024)
#define USB_MEM_BLOCK_SIZE 128
#define BOUNDARY_WORD 4
static uint32_t _FreeMemorySize;
uint32_t _AllocatedMemorySize;
#define USB_MEM_ALLOC_MAGIC 0x19685788 /* magic number in leading block */
typedef struct USB_mhdr
{
uint32_t flag; /* 0:free, 1:allocated, 0x3:first block */
uint32_t bcnt; /* if allocated, the block count of allocated memory block */
uint32_t magic;
uint32_t reserved;
} USB_MHDR_T;
uint8_t _USBMemoryPool[USB_MEMORY_POOL_SIZE] __attribute__((aligned(USB_MEM_BLOCK_SIZE)));
static USB_MHDR_T *_pCurrent;
uint32_t *_USB_pCurrent = (uint32_t *) &_pCurrent;
static uint32_t _MemoryPoolBase, _MemoryPoolEnd;
void USB_InitializeMemoryPool()
{
_MemoryPoolBase = (UINT32)&_USBMemoryPool[0] | NON_CACHE_MASK;
_MemoryPoolEnd = _MemoryPoolBase + USB_MEMORY_POOL_SIZE;
_FreeMemorySize = _MemoryPoolEnd - _MemoryPoolBase;
_AllocatedMemorySize = 0;
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase;
memset((char *)_MemoryPoolBase, 0, _FreeMemorySize);
}
int USB_available_memory()
{
return _FreeMemorySize;
}
int USB_allocated_memory()
{
return _AllocatedMemorySize;
}
void *USB_malloc(INT wanted_size, INT boundary)
{
USB_MHDR_T *pPrimitivePos = _pCurrent;
USB_MHDR_T *pFound;
INT found_size = -1;
INT i, block_count;
INT wrap = 0;
int disable_ohci_irq, disable_ehci_irq;
if (IS_OHCI_IRQ_ENABLED())
disable_ohci_irq = 1;
else
disable_ohci_irq = 0;
if (IS_EHCI_IRQ_ENABLED())
disable_ehci_irq = 1;
else
disable_ehci_irq = 0;
if (disable_ohci_irq)
DISABLE_OHCI_IRQ();
if (disable_ehci_irq)
DISABLE_EHCI_IRQ();
if (wanted_size >= _FreeMemorySize)
{
rt_kprintf("USB_malloc - want=%d, free=%d\n", wanted_size, _FreeMemorySize);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return NULL;
}
if ((UINT32)_pCurrent >= _MemoryPoolEnd)
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
do
{
if (_pCurrent->flag) /* is not a free block */
{
if (_pCurrent->magic != USB_MEM_ALLOC_MAGIC)
{
rt_kprintf("\nUSB_malloc - incorrect magic number! C:%x F:%x, wanted:%d, Base:0x%x, End:0x%x\n", (UINT32)_pCurrent, _FreeMemorySize, wanted_size, (UINT32)_MemoryPoolBase, (UINT32)_MemoryPoolEnd);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return NULL;
}
if (_pCurrent->flag == 0x3)
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + _pCurrent->bcnt * USB_MEM_BLOCK_SIZE);
else
{
rt_kprintf("USB_malloc warning - not the first block!\n");
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
}
if ((UINT32)_pCurrent > _MemoryPoolEnd)
rt_kprintf("USB_malloc - behind limit!!\n");
if ((UINT32)_pCurrent == _MemoryPoolEnd)
{
//rt_kprintf("USB_alloc - warp!!\n");
wrap = 1;
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
}
found_size = -1; /* reset the accumlator */
}
else /* is a free block */
{
if (found_size == -1) /* the leading block */
{
pFound = _pCurrent;
block_count = 1;
if (boundary > BOUNDARY_WORD)
found_size = 0; /* not use the data area of the leading block */
else
found_size = USB_MEM_BLOCK_SIZE - sizeof(USB_MHDR_T);
/* check boundary -
* If boundary > BOUNDARY_WORD, the start of next block should
* be the beginning address of allocated memory. Thus, we check
* the boundary of the next block. The leading block will be
* used as a header only.
*/
if ((boundary > BOUNDARY_WORD) &&
((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE >= _MemoryPoolEnd) ||
((((UINT32)_pCurrent) + USB_MEM_BLOCK_SIZE) % boundary != 0)))
found_size = -1; /* violate boundary, reset the accumlator */
}
else /* not the leading block */
{
found_size += USB_MEM_BLOCK_SIZE;
block_count++;
}
if (found_size >= wanted_size)
{
pFound->bcnt = block_count;
pFound->magic = USB_MEM_ALLOC_MAGIC;
_FreeMemorySize -= block_count * USB_MEM_BLOCK_SIZE;
_AllocatedMemorySize += block_count * USB_MEM_BLOCK_SIZE;
_pCurrent = pFound;
for (i = 0; i < block_count; i++)
{
_pCurrent->flag = 1; /* allocate block */
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
}
pFound->flag = 0x3;
if (boundary > BOUNDARY_WORD)
{
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
//rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size);
return (void *)((UINT32)pFound + USB_MEM_BLOCK_SIZE);
}
else
{
//USB_debug("USB_malloc(%d,%d):%x\tsize:%d, C:0x%x, %d\n", wanted_size, boundary, (UINT32)pFound + sizeof(USB_MHDR_T), block_count * USB_MEM_BLOCK_SIZE, _pCurrent, block_count);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
//rt_kprintf("- 0x%x, %d\n", (int)pFound, wanted_size);
return (void *)((UINT32)pFound + sizeof(USB_MHDR_T));
}
}
/* advance to the next block */
_pCurrent = (USB_MHDR_T *)((UINT32)_pCurrent + USB_MEM_BLOCK_SIZE);
if ((UINT32)_pCurrent >= _MemoryPoolEnd)
{
wrap = 1;
_pCurrent = (USB_MHDR_T *)_MemoryPoolBase; /* wrapped */
found_size = -1; /* reset accumlator */
}
}
}
while ((wrap == 0) || (_pCurrent < pPrimitivePos));
rt_kprintf("USB_malloc - No free memory!\n");
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return NULL;
}
void USB_free(void *alloc_addr)
{
USB_MHDR_T *pMblk;
UINT32 addr = (UINT32)alloc_addr;
INT i, count;
int disable_ohci_irq, disable_ehci_irq;
if (IS_OHCI_IRQ_ENABLED())
disable_ohci_irq = 1;
else
disable_ohci_irq = 0;
if (IS_EHCI_IRQ_ENABLED())
disable_ehci_irq = 1;
else
disable_ehci_irq = 0;
//rt_kprintf("USB_free: 0x%x\n", (int)alloc_addr);
if ((addr < _MemoryPoolBase) || (addr >= _MemoryPoolEnd))
{
if (addr)
{
rt_kprintf("[%s]Wrong!!\n", __func__);
//free(alloc_addr);
}
return;
}
if (disable_ohci_irq)
DISABLE_OHCI_IRQ();
if (disable_ehci_irq)
DISABLE_EHCI_IRQ();
//rt_kprintf("USB_free:%x\n", (INT)addr+USB_MEM_BLOCK_SIZE);
/* get the leading block address */
if (addr % USB_MEM_BLOCK_SIZE == 0)
addr -= USB_MEM_BLOCK_SIZE;
else
addr -= sizeof(USB_MHDR_T);
if (addr % USB_MEM_BLOCK_SIZE != 0)
{
rt_kprintf("USB_free fatal error on address: %x!!\n", (UINT32)alloc_addr);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return;
}
pMblk = (USB_MHDR_T *)addr;
if (pMblk->flag == 0)
{
rt_kprintf("USB_free(), warning - try to free a free block: %x\n", (UINT32)alloc_addr);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return;
}
if (pMblk->magic != USB_MEM_ALLOC_MAGIC)
{
rt_kprintf("USB_free(), warning - try to free an unknow block at address:%x.\n", addr);
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return;
}
//_pCurrent = pMblk;
//rt_kprintf("+ 0x%x, %d\n", (int)pMblk, pMblk->bcnt);
count = pMblk->bcnt;
for (i = 0; i < count; i++)
{
pMblk->flag = 0; /* release block */
pMblk = (USB_MHDR_T *)((UINT32)pMblk + USB_MEM_BLOCK_SIZE);
}
_FreeMemorySize += count * USB_MEM_BLOCK_SIZE;
_AllocatedMemorySize -= count * USB_MEM_BLOCK_SIZE;
if (disable_ohci_irq)
ENABLE_OHCI_IRQ();
if (disable_ehci_irq)
ENABLE_EHCI_IRQ();
return;
}
/// @endcond HIDDEN_SYMBOLS

View File

@ -0,0 +1,312 @@
/**************************************************************************//**
* @file usb_core.c
* @version V1.10
* $Revision: 11 $
* $Date: 14/10/03 1:54p $
* @brief USB Host library core.
*
* @note
* SPDX-License-Identifier: Apache-2.0
* Copyright (C) 2018 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "usb.h"
#include "hub.h"
/// @cond HIDDEN_SYMBOLS
USBH_T *_ohci;
HSUSBH_T *_ehci;
static UDEV_DRV_T *_drivers[MAX_UDEV_DRIVER];
static CONN_FUNC *g_conn_func, *g_disconn_func;
//extern void EHCI_IRQHandler(void);
//extern void OHCI_IRQHandler(void);
extern void nu_ohci_isr(int vector, void *param);
extern void nu_ehci_isr(int vector, void *param);
/// @endcond HIDDEN_SYMBOLS
/**
* @brief Initialize NUC980 USB Host controller and USB stack.
*
* @return None.
*/
void usbh_core_init()
{
DISABLE_EHCI_IRQ();
DISABLE_OHCI_IRQ();
_ohci = USBH;
_ehci = HSUSBH;
memset(_drivers, 0, sizeof(_drivers));
g_conn_func = NULL;
g_disconn_func = NULL;
// usbh_hub_init();
_ehci->USBPCR0 = 0x160; /* enable PHY 0 */
_ehci->USBPCR1 = 0x520; /* enable PHY 1 */
usbh_memory_init();
//_ohci->HcMiscControl |= USBH_HcMiscControl_OCAL_Msk; /* Over-current active low */
_ohci->HcMiscControl &= ~USBH_HcMiscControl_OCAL_Msk; /* Over-current active high */
#ifdef ENABLE_OHCI
//sysInstallISR(IRQ_LEVEL_1, IRQ_OHCI, (PVOID)OHCI_IRQHandler);
rt_hw_interrupt_install(IRQ_OHCI, nu_ohci_isr, NULL, "ohci");
rt_hw_interrupt_set_priority(IRQ_OHCI, IRQ_LEVEL_1);
ohci_driver.init();
ENABLE_OHCI_IRQ();
#endif
#ifdef ENABLE_EHCI
//sysInstallISR(IRQ_LEVEL_1, IRQ_EHCI, (PVOID)EHCI_IRQHandler);
rt_hw_interrupt_install(IRQ_EHCI, nu_ehci_isr, NULL, "ehci");
rt_hw_interrupt_set_priority(IRQ_EHCI, IRQ_LEVEL_1);
ehci_driver.init();
ENABLE_EHCI_IRQ();
#endif
}
/**
* @brief Let USB stack polls all root hubs. If there's any hub port
* change found, USB stack will manage the hub events in this function call.
* In this function, USB stack enumerates newly connected devices and remove staff
* of disconnected devices. User's application should periodically invoke this
* function.
* @return There's hub port change or not.
* @retval 0 No any hub port status changes found.
* @retval 1 There's hub port status changes.
*/
int usbh_polling_root_hubs(void)
{
int ret, change = 0;
#ifdef ENABLE_EHCI
do
{
ret = ehci_driver.rthub_polling();
if (ret)
change = 1;
}
while (ret == 1);
// scan_isochronous_list();
#endif
#ifdef ENABLE_OHCI
do
{
ret = ohci_driver.rthub_polling();
if (ret)
change = 1;
}
while (ret == 1);
#endif
return change;
}
/**
* @brief Force to quit an endpoint transfer.
* @param[in] udev The USB device.
* @param[in] ep The endpoint to be quit.
* @retval 0 Transfer success
* @retval < 0 Failed. Refer to error code definitions.
*/
int usbh_quit_xfer(UDEV_T *udev, EP_INFO_T *ep)
{
return udev->hc_driver->quit_xfer(NULL, ep);
}
int usbh_connect_device(UDEV_T *udev)
{
usbh_delay_ms(100); /* initially, give 100 ms delay */
if (g_conn_func)
g_conn_func(udev, 0);
return 0;
}
void usbh_disconnect_device(UDEV_T *udev)
{
USB_debug("disconnect device...\n");
if (g_disconn_func)
g_disconn_func(udev, 0);
#if 1 //CHECK: Maybe create a new API to quit_xfer and free udev for application
usbh_quit_xfer(udev, &(udev->ep0)); /* Quit control transfer if hw_pipe is not NULL. */
/* remove device from global device list */
// free_dev_address(udev->dev_num);
free_device(udev);
// usbh_memory_used();
#endif
}
/**
* @brief Install device connect and disconnect callback function.
*
* @param[in] conn_func Device connect callback function.
* @param[in] disconn_func Device disconnect callback function.
* @return None.
*/
void usbh_install_conn_callback(CONN_FUNC *conn_func, CONN_FUNC *disconn_func)
{
g_conn_func = conn_func;
g_disconn_func = disconn_func;
}
int usbh_reset_port(UDEV_T *udev)
{
if (udev->parent == NULL)
{
if (udev->hc_driver)
return udev->hc_driver->rthub_port_reset(udev->port_num - 1);
else
return USBH_ERR_NOT_FOUND;
}
else
{
return udev->parent->port_reset(udev->parent, udev->port_num);
}
}
/**
* @brief Force to quit an UTR transfer.
* @param[in] utr The UTR transfer to be quit.
* @retval 0 Transfer success
* @retval < 0 Failed. Refer to error code definitions.
*/
int usbh_quit_utr(UTR_T *utr)
{
if (!utr || !utr->udev)
return USBH_ERR_NOT_FOUND;
return utr->udev->hc_driver->quit_xfer(utr, NULL);
}
/**
* @brief Execute an USB request in control transfer. This function returns after the request
* was done or aborted.
* @param[in] udev The target USB device.
* @param[in] bmRequestType Characteristics of request
* @param[in] bRequest Specific request
* @param[in] wValue Word-sized field that varies according to request
* @param[in] wIndex Word-sized field that varies according to request
* @param[in] wLength Number of bytes to transfer if there is a Data stage
* @param[in] buff Data buffer used in data stage
* @param[out] xfer_len Transmitted/received length of data
* @param[in] timeout Time-out limit (in 10ms - timer tick) of this transfer
* @retval 0 Transfer success
* @retval < 0 Transfer failed. Refer to error code definitions.
*/
int usbh_ctrl_xfer(UDEV_T *udev, uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
uint16_t wLength, uint8_t *buff, uint32_t *xfer_len, uint32_t timeout)
{
UTR_T *utr;
uint32_t t0, timeout_tick;
int status;
*xfer_len = 0;
//if (check_device(udev))
// return USBH_ERR_INVALID_PARAM;
utr = alloc_utr(udev);
if (utr == NULL)
return USBH_ERR_MEMORY_OUT;
utr->setup.bmRequestType = bmRequestType;
utr->setup.bRequest = bRequest;
utr->setup.wValue = wValue;
utr->setup.wIndex = wIndex;
utr->setup.wLength = wLength;
utr->buff = buff;
utr->data_len = wLength;
utr->bIsTransferDone = 0;
status = udev->hc_driver->ctrl_xfer(utr);
if (status < 0)
{
udev->ep0.hw_pipe = NULL;
free_utr(utr);
return status;
}
timeout_tick = usbh_tick_from_millisecond(timeout);
t0 = usbh_get_ticks();
while (utr->bIsTransferDone == 0)
{
if (usbh_get_ticks() - t0 > timeout_tick)
{
usbh_quit_utr(utr);
free_utr(utr);
udev->ep0.hw_pipe = NULL;
return USBH_ERR_TIMEOUT;
}
}
status = utr->status;
if (status == 0)
{
*xfer_len = utr->xfer_len;
}
free_utr(utr);
return status;
}
/**
* @brief Execute a bulk transfer request. This function will return immediately after
* issued the bulk transfer. USB stack will later call back utr->func() once the bulk
* transfer was done or aborted.
* @param[in] utr The bulk transfer request.
* @retval 0 Transfer success
* @retval < 0 Failed. Refer to error code definitions.
*/
int usbh_bulk_xfer(UTR_T *utr)
{
return utr->udev->hc_driver->bulk_xfer(utr);
}
/**
* @brief Execute an interrupt transfer request. This function will return immediately after
* issued the interrupt transfer. USB stack will later call back utr->func() once the
* interrupt transfer was done or aborted.
* @param[in] utr The interrupt transfer request.
* @retval 0 Transfer success
* @retval < 0 Failed. Refer to error code definitions.
*/
int usbh_int_xfer(UTR_T *utr)
{
return utr->udev->hc_driver->int_xfer(utr);
}

View File

@ -114,13 +114,6 @@ config SOC_SERIES_NUC980
help
Choose this option if you need TIMER function mode.
config BSP_USING_TPWM0
select BSP_USING_TPWM
select RT_USING_PWM
bool "TIMER PWM"
help
Choose this option if you need PWM function mode.
config BSP_USING_TIMER0_CAPTURE
select BSP_USING_TIMER_CAPTURE
select RT_USING_INPUT_CAPTURE
@ -146,13 +139,6 @@ config SOC_SERIES_NUC980
help
Choose this option if you need TIMER function mode.
config BSP_USING_TPWM1
select BSP_USING_TPWM
select RT_USING_PWM
bool "TIMER PWM"
help
Choose this option if you need PWM function mode.
config BSP_USING_TIMER1_CAPTURE
select BSP_USING_TIMER_CAPTURE
select RT_USING_INPUT_CAPTURE
@ -177,13 +163,6 @@ config SOC_SERIES_NUC980
help
Choose this option if you need TIMER function mode.
config BSP_USING_TPWM2
select BSP_USING_TPWM
select RT_USING_PWM
bool "TIMER PWM"
help
Choose this option if you need PWM function mode.
config BSP_USING_TIMER2_CAPTURE
select BSP_USING_TIMER_CAPTURE
select RT_USING_INPUT_CAPTURE
@ -208,13 +187,6 @@ config SOC_SERIES_NUC980
help
Choose this option if you need TIMER function mode.
config BSP_USING_TPWM3
select BSP_USING_TPWM
select RT_USING_PWM
bool "TIMER PWM"
help
Choose this option if you need PWM function mode.
config BSP_USING_TIMER3_CAPTURE
select BSP_USING_TIMER_CAPTURE
select RT_USING_INPUT_CAPTURE
@ -239,13 +211,6 @@ config SOC_SERIES_NUC980
help
Choose this option if you need TIMER function mode.
config BSP_USING_TPWM4
select BSP_USING_TPWM
select RT_USING_PWM
bool "TIMER PWM"
help
Choose this option if you need PWM function mode.
config BSP_USING_TIMER4_CAPTURE
select BSP_USING_TIMER_CAPTURE
select RT_USING_INPUT_CAPTURE
@ -634,9 +599,4 @@ config SOC_SERIES_NUC980
config BSP_USING_USBH
bool "Enable USB Host Controller(USBH)"
select RT_USING_USB_HOST
select RT_USBH_MSTORAGE
config BSP_USING_OTG
bool "Enable USB On-The-Go(OTG)"
select BSP_USING_USBH
select BSP_USING_USBD
select RT_USBH_MSTORAGE

View File

@ -9,6 +9,6 @@ CPPPATH = [cwd]
group = []
# USB driver constrain
group = DefineGroup('nuc980_rttport', src, depend = [''], CPPPATH = CPPPATH)
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -22,22 +22,11 @@ static struct mem_desc hw_mem_desc[] =
{ 0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB }, /* None cached for 4G memory */
{ 0x00000000, BOARD_SDRAM_SIZE - 1, 0x00000000, RW_CB }, /* 64M cached DDR memory */
{ BIT31, (BIT31 | BOARD_SDRAM_SIZE) - 1, BIT31, RW_NCNB }, /* Shadow DDR Map */
{ 0x3C000000, 0x3C00E000 - 1, 0x3C000000, RW_NCNB }, /* 56K SRAM memory */
{ 0xBC000000, 0xBC00E000 - 1, 0xBC000000, RW_NCNB } /* 56K Shadow memory */
{ 0x3C000000, 0x3C004000 - 1, 0x3C000000, RW_NCNB }, /* 16K SRAM memory */
{ 0xBC000000, 0xBC004000 - 1, 0xBC000000, RW_NCNB } /* 16K Shadow memory */
};
#endif
void nu_clock_base_dump(void)
{
rt_kprintf("SYS_UPLL = %d\n", sysGetClock(SYS_UPLL));
rt_kprintf("SYS_APLL = %d\n", sysGetClock(SYS_APLL));
rt_kprintf("SYS_SYSTEM = %d\n", sysGetClock(SYS_SYSTEM));
rt_kprintf("SYS_HCLK = %d\n", sysGetClock(SYS_HCLK));
rt_kprintf("SYS_PCLK01 = %d\n", sysGetClock(SYS_PCLK01));
rt_kprintf("SYS_PCLK2 = %d\n", sysGetClock(SYS_PCLK2));
rt_kprintf("SYS_CPU = %d\n", sysGetClock(SYS_CPU));
}
/**
* This function will initial M487 board.
*/
@ -52,6 +41,12 @@ RT_WEAK void rt_hw_board_init(void)
#if defined(BSP_USING_MMU)
/* initialize mmu */
rt_hw_mmu_init(&hw_mem_desc[0], sizeof(hw_mem_desc) / sizeof(hw_mem_desc[0]));
#else
/* disable I/D cache */
mmu_disable_dcache();
mmu_disable_icache();
mmu_disable();
mmu_invalidate_tlb();
#endif
/* initialize hardware interrupt */
@ -72,9 +67,6 @@ RT_WEAK void rt_hw_board_init(void)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
nu_clock_base_dump();
rt_kprintf("HEAP_START=0x%08x, HEAP_END=0x%08x\n", BOARD_HEAP_START, BOARD_HEAP_END);
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif

View File

@ -75,6 +75,7 @@ static rt_err_t nu_aes_crypt_run(
{
uint32_t au32SwapKey[8];
uint32_t au32SwapIV[4];
rt_err_t result;
au32SwapKey[0] = nu_get32_be(&pu8Key[0]);
au32SwapKey[1] = nu_get32_be(&pu8Key[4]);
@ -98,7 +99,8 @@ static rt_err_t nu_aes_crypt_run(
au32SwapIV[2] = nu_get32_be(&pu8IV[8]);
au32SwapIV[3] = nu_get32_be(&pu8IV[12]);
rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_AES_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
AES_Open(CRPT, bEncrypt, u32OpMode, u32KeySize, AES_IN_OUT_SWAP);
AES_SetKey(CRPT, (uint32_t *)&au32SwapKey[0], u32KeySize);
@ -137,7 +139,8 @@ static rt_err_t nu_aes_crypt_run(
/* Clear AES interrupt status */
AES_CLR_INT_FLAG(CRPT);
rt_mutex_release(&s_AES_mutex);
result = rt_mutex_release(&s_AES_mutex);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}
@ -145,19 +148,25 @@ static rt_err_t nu_aes_crypt_run(
//Using PRNG instead of TRNG
static void nu_prng_open(uint32_t u32Seed)
{
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
rt_err_t result;
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
//Open PRNG 64 bits. But always return 32 bits
PRNG_Open(CRPT, PRNG_KEY_SIZE_64, PRNG_SEED_RELOAD, u32Seed);
rt_mutex_release(&s_PRNG_mutex);
result = rt_mutex_release(&s_PRNG_mutex);
RT_ASSERT(result == RT_EOK);
}
static rt_uint32_t nu_prng_run(void)
{
uint32_t au32RNGValue[2];
rt_err_t result;
rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_PRNG_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
PRNG_Start(CRPT);
while ((CRPT->PRNG_CTL & CRPT_PRNG_CTL_BUSY_Msk)) {};
@ -167,7 +176,8 @@ static rt_uint32_t nu_prng_run(void)
PRNG_Read(CRPT, &au32RNGValue[0]);
rt_mutex_release(&s_PRNG_mutex);
result = rt_mutex_release(&s_PRNG_mutex);
RT_ASSERT(result == RT_EOK);
return au32RNGValue[0];
}
@ -340,10 +350,13 @@ static rt_err_t nu_sha_hash_run(
uint32_t u32DataLen
)
{
rt_err_t result;
RT_ASSERT(psSHACtx != RT_NULL);
RT_ASSERT(pu8InData != RT_NULL);
rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
result = rt_mutex_take(&s_SHA_mutex, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
uint8_t *pu8SrcAddr = (uint8_t *)pu8InData;
uint32_t u32CopyLen = 0;
@ -383,7 +396,8 @@ static rt_err_t nu_sha_hash_run(
if (psSHACtx->pu8SHATempBuf == RT_NULL)
{
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return -RT_ENOMEM;
}
@ -411,7 +425,8 @@ static rt_err_t nu_sha_hash_run(
if (psSHACtx->pu8SHATempBuf == RT_NULL)
{
LOG_E("fun[%s] memory allocate %d bytes failed!", __FUNCTION__, psSHACtx->u32BlockSize);
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return -RT_ENOMEM;
}
@ -422,7 +437,8 @@ static rt_err_t nu_sha_hash_run(
psSHACtx->u32SHATempBufLen += u32DataLen;
}
rt_mutex_release(&s_SHA_mutex);
result = rt_mutex_release(&s_SHA_mutex);
RT_ASSERT(result == RT_EOK);
return RT_EOK;
}

View File

@ -232,7 +232,6 @@ static void link_monitor(void *param)
nu_emac_t psNuEmac = (nu_emac_t)param;
EMAC_T *EMAC = psNuEmac->memmgr.psEmac;
uint32_t LinkStatus_Last = EMAC_LINK_DOWN;
rt_err_t result = RT_EOK;
EMAC_PhyInit(EMAC);
@ -274,9 +273,6 @@ static void link_monitor(void *param)
else
{
eth_device_linkchange(&psNuEmac->eth, RT_TRUE);
result = rt_sem_release(&psNuEmac->eth_sem);
RT_ASSERT(result == RT_EOK);
}
LinkStatus_Last = LinkStatus_Current;
@ -317,7 +313,8 @@ static rt_err_t nu_emac_init(rt_device_t dev)
snprintf(szTmp, sizeof(szTmp), "%sphy", psNuEmac->name);
rt_sem_init(&psNuEmac->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
ret = rt_sem_init(&psNuEmac->eth_sem, "eth_sem", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
EMAC_Reset(EMAC);
@ -402,26 +399,21 @@ static rt_err_t nu_emac_tx(rt_device_t dev, struct pbuf *p)
rt_uint32_t offset = 0;
rt_uint8_t *buf;
if (psNuEmac->eth.link_status == RT_FALSE)
{
rt_kprintf("[%s]Stand here.\n", psNuEmac->name);
while (rt_sem_take(&psNuEmac->eth_sem, RT_WAITING_FOREVER) != RT_EOK);
rt_kprintf("[%s]Leave.\n", psNuEmac->name);
}
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr);
/* Get free TX buffer */
if (buf == RT_NULL)
{
rt_sem_control(&psNuEmac->eth_sem, RT_IPC_CMD_RESET, 0);
rt_err_t result;
result = rt_sem_control(&psNuEmac->eth_sem, RT_IPC_CMD_RESET, 0);
RT_ASSERT(result != RT_EOK);
EMAC_CLEAR_INT_FLAG(EMAC, EMAC_INTSTS_TXCPIF_Msk);
EMAC_ENABLE_INT(EMAC, EMAC_INTEN_TXCPIEN_Msk);
do
{
rt_sem_take(&psNuEmac->eth_sem, 1);
result = rt_sem_take(&psNuEmac->eth_sem, 10);
buf = (rt_uint8_t *)EMAC_ClaimFreeTXBuf(&psNuEmac->memmgr);
}
while (buf == RT_NULL);

View File

@ -0,0 +1,240 @@
/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-1-28 Wayne First version
*
******************************************************************************/
#include <rtconfig.h>
#if defined(BSP_USING_TIMER_CAPTURE)
#include <rtdevice.h>
#include <NuMicro.h>
#include <drv_sys.h>
/* Private define ---------------------------------------------------------------*/
/* Timer prescale setting. Since it will affect the pulse width of measure, it is recommended to set to 2. */
#define PSC_DIV (2)
#define NU_TCAP_DEVICE(etimer) (nu_capture_t*)(etimer)
enum
{
TCAP_START = -1,
#if defined(BSP_USING_TIMER0_CAPTURE)
TCAP0_IDX,
#endif
#if defined(BSP_USING_TIMER1_CAPTURE)
TCAP1_IDX,
#endif
#if defined(BSP_USING_TIMER2_CAPTURE)
TCAP2_IDX,
#endif
#if defined(BSP_USING_TIMER3_CAPTURE)
TCAP3_IDX,
#endif
#if defined(BSP_USING_TIMER4_CAPTURE)
TCAP4_IDX,
#endif
/* BSP_USING_TIMER5 is reserved for Systick usage. */
TCAP_CNT
};
/* Private typedef --------------------------------------------------------------*/
typedef struct _timer
{
struct rt_inputcapture_device parent;
char *name;
uint32_t idx;
IRQn_Type irqn;
E_SYS_IPRST rstidx;
E_SYS_IPCLK clkidx;
uint32_t u32CurrentCnt;
} nu_capture_t;
/* Private functions ------------------------------------------------------------*/
static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture);
static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture);
static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture);
static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us);
/* Public functions -------------------------------------------------------------*/
/* Private variables ------------------------------------------------------------*/
static nu_capture_t nu_etcap_arr [] =
{
#if defined(BSP_USING_TIMER0_CAPTURE)
{
.name = "timer0i0",
.idx = 0,
.irqn = IRQ_TIMER0,
.rstidx = TIMER0RST,
.clkidx = TIMER0CKEN,
},
#endif
#if defined(BSP_USING_TIMER1_CAPTURE)
{
.name = "timer1i0",
.idx = 1,
.irqn = IRQ_TIMER1,
.rstidx = TIMER1RST,
.clkidx = TIMER1CKEN,
},
#endif
#if defined(BSP_USING_TIMER2_CAPTURE)
{
.name = "timer2i0",
.idx = 2,
.irqn = IRQ_TIMER2,
.rstidx = TIMER2RST,
.clkidx = TIMER2CKEN,
},
#endif
#if defined(BSP_USING_TIMER3_CAPTURE)
{
.name = "timer3i0",
.idx = 3,
.irqn = IRQ_TIMER3,
.rstidx = TIMER3RST,
.clkidx = TIMER3CKEN,
},
#endif
#if defined(BSP_USING_TIMER4_CAPTURE)
{
.name = "timer4i0",
.idx = 4,
.irqn = IRQ_TIMER4,
.rstidx = TIMER4RST,
.clkidx = TIMER4CKEN,
},
#endif
/* BSP_USING_TIMER5 is reserved for Systick usage. */
};
static struct rt_inputcapture_ops nu_capture_ops =
{
.init = nu_capture_init,
.open = nu_capture_open,
.close = nu_capture_close,
.get_pulsewidth = nu_capture_get_pulsewidth,
};
/* Functions define ------------------------------------------------------------*/
static void nu_tcap_isr(int vector, void *param)
{
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(param);
RT_ASSERT(psNuTCap != RT_NULL);
ETIMER_ClearCaptureIntFlag(psNuTCap->idx);
/* Report caputring data and level. */
psNuTCap->u32CurrentCnt = ETIMER_GetCaptureData(psNuTCap->idx);
rt_hw_inputcapture_isr(&psNuTCap->parent, ETIMER_GetCaptureFallingEdgeFlag(psNuTCap->idx));
}
static rt_err_t nu_capture_get_pulsewidth(struct rt_inputcapture_device *inputcapture, rt_uint32_t *pulsewidth_us)
{
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
RT_ASSERT(inputcapture != RT_NULL);
RT_ASSERT(pulsewidth_us != RT_NULL);
*pulsewidth_us = psNuTCap->u32CurrentCnt / PSC_DIV;
return RT_EOK;
}
static rt_err_t nu_capture_init(struct rt_inputcapture_device *inputcapture)
{
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
RT_ASSERT(inputcapture != RT_NULL);
nu_sys_ipclk_enable(psNuTCap->clkidx);
nu_sys_ip_reset(psNuTCap->rstidx);
return RT_EOK;
}
static uint8_t cal_time_prescale(nu_capture_t *psNuTCap)
{
uint32_t u32Clk = ETIMER_GetModuleClock(psNuTCap->idx);
/* 1 tick = 1/PSC_DIV us */
return (u32Clk / 1000000 / PSC_DIV) - 1;
}
static rt_err_t nu_capture_open(struct rt_inputcapture_device *inputcapture)
{
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
RT_ASSERT(inputcapture != RT_NULL);
/* Enable Timer Interrupt */
rt_hw_interrupt_umask(psNuTCap->irqn);
/* Clear counter before openning. */
ETIMER_ClearCounter(psNuTCap->idx);
ETIMER_Open(psNuTCap->idx, ETIMER_CONTINUOUS_MODE, 1);
ETIMER_SET_PRESCALE_VALUE(psNuTCap->idx, cal_time_prescale(psNuTCap));
ETIMER_SET_CMP_VALUE(psNuTCap->idx, 0xFFFFFF);
ETIMER_EnableCapture(psNuTCap->idx, ETIMER_CAPTURE_COUNTER_RESET_MODE, ETIMER_CAPTURE_RISING_THEN_FALLING_EDGE);
ETIMER_EnableCaptureInt(psNuTCap->idx);
ETIMER_Start(psNuTCap->idx);
return RT_EOK;
}
static rt_err_t nu_capture_close(struct rt_inputcapture_device *inputcapture)
{
nu_capture_t *psNuTCap = NU_TCAP_DEVICE(inputcapture);
RT_ASSERT(inputcapture != RT_NULL);
ETIMER_Stop(psNuTCap->idx);
ETIMER_DisableCaptureInt(psNuTCap->idx);
ETIMER_Close(psNuTCap->idx);
rt_hw_interrupt_mask(psNuTCap->irqn);
return RT_EOK;
}
/* Init and register timer capture */
static int nu_timer_capture_device_init(void)
{
int i;
for (i = (TCAP_START + 1); i < TCAP_CNT; i++)
{
/* Register operations */
nu_etcap_arr[i].parent.ops = &nu_capture_ops;
/* Install ISR */
rt_hw_interrupt_install(nu_etcap_arr[i].irqn, nu_tcap_isr, &nu_etcap_arr[i], nu_etcap_arr[i].name);
/* Register inputcapture device */
rt_device_inputcapture_register(&nu_etcap_arr[i].parent, nu_etcap_arr[i].name, &nu_etcap_arr[i]);
}
return 0;
}
INIT_DEVICE_EXPORT(nu_timer_capture_device_init);
#endif //#if defined(BSP_USING_TIMER_CAPTURE)

View File

@ -968,8 +968,12 @@ static void nu_pdma_memfun_actor_init(void)
{
nu_pdma_memfun_actor_maxnum = i;
nu_pdma_memfun_actor_mask = ~(((1 << i) - 1));
nu_pdma_memfun_actor_pool_sem = rt_sem_create("mempool_sem", nu_pdma_memfun_actor_maxnum, RT_IPC_FLAG_FIFO);
RT_ASSERT(nu_pdma_memfun_actor_pool_sem != RT_NULL);
nu_pdma_memfun_actor_pool_lock = rt_mutex_create("mempool_lock", RT_IPC_FLAG_FIFO);
RT_ASSERT(nu_pdma_memfun_actor_pool_lock != RT_NULL);
}
}
@ -987,13 +991,15 @@ static void nu_pdma_memfun_cb(void *pvUserData, uint32_t u32Events)
static int nu_pdma_memfun_employ(void)
{
int idx = -1 ;
rt_err_t result = 0;
rt_err_t result = RT_EOK;
/* Headhunter */
if (nu_pdma_memfun_actor_pool_sem &&
((result = rt_sem_take(nu_pdma_memfun_actor_pool_sem, RT_WAITING_FOREVER)) == RT_EOK))
{
rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
result = rt_mutex_take(nu_pdma_memfun_actor_pool_lock, RT_WAITING_FOREVER);
RT_ASSERT(result == RT_EOK);
/* Find the position of first '0' in nu_pdma_memfun_actor_mask. */
idx = nu_cto(nu_pdma_memfun_actor_mask);
if (idx != 32)
@ -1004,9 +1010,9 @@ static int nu_pdma_memfun_employ(void)
{
idx = -1;
}
rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
result = rt_mutex_release(nu_pdma_memfun_actor_pool_lock);
RT_ASSERT(result == RT_EOK);
}
RT_ASSERT(result == RT_EOK);
return idx;
}

View File

@ -301,42 +301,4 @@ int rt_hw_pwm_init(void)
INIT_DEVICE_EXPORT(rt_hw_pwm_init);
#if defined(RT_USING_FINSH)
#include <finsh.h>
#ifdef FINSH_USING_MSH
static int pwm_get(int argc, char **argv)
{
int result = 0;
struct rt_device_pwm *device = RT_NULL;
struct rt_pwm_configuration configuration = {0};
if (argc != 3)
{
rt_kprintf("Usage: pwm_get pwm1 1\n");
result = -RT_ERROR;
goto _exit;
}
device = (struct rt_device_pwm *)rt_device_find(argv[1]);
if (!device)
{
result = -RT_EIO;
goto _exit;
}
configuration.channel = atoi(argv[2]);
result = rt_device_control(&device->parent, PWM_CMD_GET, &configuration);
_exit:
return result;
}
MSH_CMD_EXPORT(pwm_get, pwm_get pwm1 1);
#endif /* FINSH_USING_MSH */
#endif /* RT_USING_FINSH */
#endif

View File

@ -60,7 +60,7 @@ static struct nu_spi nu_qspi_arr [] =
.rstidx = QSPI0RST,
.clkidx = QSPI0CKEN,
#if defined(BSP_USING_QSPI_PDMA)
#if defined(BSP_USING_SPI_PDMA)
#if defined(BSP_USING_QSPI0_PDMA)
.pdma_perp_tx = PDMA_QSPI0_TX,
.pdma_perp_rx = PDMA_QSPI0_RX,
@ -153,7 +153,6 @@ exit_nu_qspi_bus_configure:
return -(ret);
}
#if defined(RT_SFUD_USING_QSPI)
static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8_t *rx, int qspi_lines)
{
QSPI_T *qspi_base = (QSPI_T *)qspi_bus->spi_base;
@ -197,16 +196,13 @@ static int nu_qspi_mode_config(struct nu_spi *qspi_bus, rt_uint8_t *tx, rt_uint8
}
return qspi_lines;
}
#endif
static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
struct nu_spi *qspi_bus;
struct rt_qspi_configuration *qspi_configuration;
#if defined(RT_SFUD_USING_QSPI)
struct rt_qspi_message *qspi_message;
rt_uint8_t u8last = 1;
#endif
rt_uint8_t bytes_per_word;
QSPI_T *qspi_base;
rt_uint32_t u32len = 0;
@ -232,7 +228,6 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
}
}
#if defined(RT_SFUD_USING_QSPI)
qspi_message = (struct rt_qspi_message *)message;
/* Command + Address + Dummy + Data */
@ -248,7 +243,7 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
}
/* Address stage */
if (qspi_message->address.size != 0)
if (qspi_message->address.size > 0)
{
rt_uint32_t u32ReversedAddr = 0;
rt_uint32_t u32AddrNumOfByte = qspi_message->address.size / 8;
@ -278,8 +273,39 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
1);
}
/* alternate_bytes stage */
if ((qspi_message->alternate_bytes.size > 0) && (qspi_message->alternate_bytes.size <= 4))
{
rt_uint32_t u32AlternateByte = 0;
rt_uint32_t u32NumOfByte = qspi_message->alternate_bytes.size / 8;
switch (u32NumOfByte)
{
case 1:
u32AlternateByte = (qspi_message->alternate_bytes.content & 0xff);
break;
case 2:
nu_set16_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
break;
case 3:
nu_set24_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
break;
case 4:
nu_set32_be((rt_uint8_t *)&u32AlternateByte, qspi_message->alternate_bytes.content);
break;
default:
RT_ASSERT(0);
break;
}
u8last = nu_qspi_mode_config(qspi_bus, (rt_uint8_t *)&u32AlternateByte, RT_NULL, qspi_message->alternate_bytes.qspi_lines);
nu_spi_transfer((struct nu_spi *)qspi_bus,
(rt_uint8_t *) &u32AlternateByte,
RT_NULL,
u32NumOfByte,
1);
}
/* Dummy_cycles stage */
if (qspi_message->dummy_cycles != 0)
if (qspi_message->dummy_cycles > 0)
{
qspi_bus->dummy = 0x00;
@ -291,12 +317,10 @@ static rt_uint32_t nu_qspi_bus_xfer(struct rt_spi_device *device, struct rt_spi_
1);
}
/* Data stage */
nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
#endif //#if defined(RT_SFUD_USING_QSPI)
if (message->length != 0)
if (message->length > 0)
{
/* Data stage */
nu_qspi_mode_config(qspi_bus, (rt_uint8_t *) message->send_buf, (rt_uint8_t *) message->recv_buf, qspi_message->qspi_data_lines);
nu_spi_transfer((struct nu_spi *)qspi_bus,
(rt_uint8_t *) message->send_buf,
(rt_uint8_t *) message->recv_buf,

View File

@ -412,7 +412,8 @@ static int rt_hw_sdh_init(void)
rt_err_t ret = RT_EOK;
rt_uint32_t flags = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE;
rt_event_init(&sdh_event, "sdh_event", RT_IPC_FLAG_FIFO);
ret = rt_event_init(&sdh_event, "sdh_event", RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
for (i = (SDH_START + 1); i < SDH_CNT; i++)
{
@ -428,7 +429,8 @@ static int rt_hw_sdh_init(void)
/* Private */
nu_sdh_arr[i].dev.user_data = (void *)&nu_sdh_arr[i];
rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
ret = rt_sem_init(&nu_sdh_arr[i].lock, "sdhlock", 1, RT_IPC_FLAG_FIFO);
RT_ASSERT(ret == RT_EOK);
rt_hw_interrupt_install(nu_sdh_arr[i].irqn, SDH_IRQHandler, (void *)&nu_sdh_arr[i], nu_sdh_arr[i].name);
rt_hw_interrupt_umask(nu_sdh_arr[i].irqn);
@ -437,9 +439,8 @@ static int rt_hw_sdh_init(void)
nu_sys_ip_reset(nu_sdh_arr[i].rstidx);
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
nu_sdh_arr[i].pbuf = RT_NULL;
ret = rt_device_register(&nu_sdh_arr[i].dev, nu_sdh_arr[i].name, flags);
RT_ASSERT(ret == RT_EOK);
}
@ -591,7 +592,10 @@ static void sdh_hotplugger(void *param)
for (i = (SDH_START + 1); i < SDH_CNT; i++)
{
if (SDH_IS_CARD_PRESENT(nu_sdh_arr[i].base))
/* Try to detect SD card on selected port. */
SDH_Open(nu_sdh_arr[i].base, CardDetect_From_GPIO);
if (!SDH_Probe(nu_sdh_arr[i].base) &&
SDH_IS_CARD_PRESENT(nu_sdh_arr[i].base))
{
nu_sdh_hotplug_mount(&nu_sdh_arr[i]);
}

View File

@ -287,6 +287,18 @@ void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx)
_nu_sys_ipclk(eIPClkIdx, 0);
}
E_SYS_USB0_ID nu_sys_usb0_role(void)
{
/* Check Role on USB0 dual-role port. */
/*
[17] USB0_IDS
USB0_ID Status
0 = USB port 0 used as a USB device port.
1 = USB port 0 used as a USB host port.
*/
return ((inpw(REG_SYS_MISCISR) & (1 << 17)) > 0) ? USB0_ID_HOST : USB0_ID_DEVICE;
}
#ifdef RT_USING_FINSH
#include <finsh.h>
@ -308,6 +320,32 @@ int cmd_shutdown(int argc, char **argv)
FINSH_FUNCTION_EXPORT_ALIAS(cmd_reset, __cmd_reset, restart the system.);
FINSH_FUNCTION_EXPORT_ALIAS(cmd_shutdown, __cmd_shutdown, shutdown the system.);
int nu_clocks(int argc, char **argv)
{
rt_kprintf("SYS_UPLL = %d MHz\n", sysGetClock(SYS_UPLL));
rt_kprintf("SYS_APLL = %d MHz\n", sysGetClock(SYS_APLL));
rt_kprintf("SYS_SYSTEM = %d MHz\n", sysGetClock(SYS_SYSTEM));
rt_kprintf("SYS_HCLK = %d MHz\n", sysGetClock(SYS_HCLK));
rt_kprintf("SYS_PCLK01 = %d MHz\n", sysGetClock(SYS_PCLK01));
rt_kprintf("SYS_PCLK2 = %d MHz\n", sysGetClock(SYS_PCLK2));
rt_kprintf("SYS_CPU = %d MHz\n", sysGetClock(SYS_CPU));
rt_kprintf("CLK_HCLKEN = %08X\n", inpw(REG_CLK_HCLKEN));
rt_kprintf("CLK_PCLKEN0 = %08X\n", inpw(REG_CLK_PCLKEN0));
rt_kprintf("CLK_PCLKEN1 = %08X\n", inpw(REG_CLK_PCLKEN1));
rt_kprintf("AIC_INTMSK0 = %08X\n", inpw(REG_AIC_INTMSK0));
rt_kprintf("AIC_INTMSK1 = %08X\n", inpw(REG_AIC_INTMSK1));
rt_kprintf("AIC_INTEN0 = %08X\n", inpw(REG_AIC_INTEN0));
rt_kprintf("AIC_INTEN1 = %08X\n", inpw(REG_AIC_INTEN1));
rt_kprintf("AIC_INTDIS0 = %08X\n", inpw(REG_AIC_INTDIS0));
rt_kprintf("AIC_INTDIS1 = %08X\n", inpw(REG_AIC_INTDIS1));
return 0;
}
MSH_CMD_EXPORT(nu_clocks, Get all system clocks);
#endif
#endif

View File

@ -243,6 +243,13 @@ typedef enum
} E_SYS_IPCLK;
typedef enum
{
USB0_ID_DEVICE,
USB0_ID_HOST,
USB0_ID_CNT
} E_SYS_USB0_ID;
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_set_priority(int vector, int priority);
void rt_hw_interrupt_set_type(int vector, int type);
@ -255,5 +262,6 @@ void nu_systick_udelay(uint32_t delay_us);
void nu_sys_ip_reset(E_SYS_IPRST eIPRstIdx);
void nu_sys_ipclk_enable(E_SYS_IPCLK eIPClkIdx);
void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx);
E_SYS_USB0_ID nu_sys_usb0_role(void);
#endif

View File

@ -572,7 +572,6 @@ static void nu_pdma_uart_rx_cb(void *pvOwner, uint32_t u32Events)
struct rt_serial_device *serial = (struct rt_serial_device *)pvOwner;
nu_uart_t puart = (nu_uart_t)serial;
RT_ASSERT(serial != RT_NULL);
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
/* Get base address of uart register */
UART_T *uart_base = puart->uart_base;
@ -581,6 +580,9 @@ static void nu_pdma_uart_rx_cb(void *pvOwner, uint32_t u32Events)
if (u32Events & (NU_PDMA_EVENT_TRANSFER_DONE | NU_PDMA_EVENT_TIMEOUT))
{
#if defined(BSP_USING_MMU)
struct rt_serial_rx_fifo *rx_fifo = (struct rt_serial_rx_fifo *)serial->serial_rx;
#endif
if (u32Events & NU_PDMA_EVENT_TRANSFER_DONE)
{
transferred_rxbyte = puart->rxdma_trigger_len;

View File

@ -23,9 +23,9 @@
#include "drv_sys.h"
#define LOG_TAG "drv.usbd"
#define DBG_ENABLE
//#define DBG_ENABLE
#define DBG_SECTION_NAME "drv.usbd"
#define DBG_LEVEL DBG_INFO
//#define DBG_LEVEL DBG_ERROR
#define DBG_COLOR
#include <rtdbg.h>
@ -124,7 +124,8 @@ typedef struct _nu_usbd_t
IRQn_Type irqn;
E_SYS_IPRST rstidx;
E_SYS_IPCLK clkidx;
uint8_t address_tmp; /* Keep assigned address for flow control */
uint8_t address_tmp; /* Keep assigned address for flow control */
uint8_t plugging_status; /* For debounce, 0: Unplug, 1: plug-in */
} nu_usbd_t;
@ -149,6 +150,7 @@ static nu_usbd_t nu_usbd =
.rstidx = USBDRST,
.clkidx = USBDCKEN,
.address_tmp = 0,
.plugging_status = 0,
};
static struct udcd _rt_obj_udc;
@ -278,6 +280,27 @@ static void NU_SetupStageCallback(nu_usbd_t *nu_udc)
rt_usbd_ep0_setup_handler(&_rt_obj_udc, (struct urequest *)&setup_packet);
}
__STATIC_INLINE void nu_udc_enable(void)
{
USBD_ENABLE_USB();
}
__STATIC_INLINE void nu_udc_disable(void)
{
int i;
USBD_ENABLE_CEP_INT(0);
USBD_CLR_CEP_INT_FLAG(0xffff);
USBD_SET_CEP_STATE(inpw(REG_USBD_CEPCTL) | USB_CEPCTL_FLUSH);
for (i = 0; i < USBD_MAX_EP; i++)
USBD->EP[i].EPRSPCTL = USB_EP_RSPCTL_FLUSH | USB_EP_RSPCTL_TOGGLE;
USBD_DISABLE_USB();
}
static rt_err_t _ep_set_stall(rt_uint8_t address)
{
@ -543,6 +566,9 @@ static void nu_usbd_isr(int vector, void *param)
int i;
int IrqStAllEP;
/* Igrone event if role is USBH*/
if (nu_sys_usb0_role() != USB0_ID_DEVICE) return;
IrqStL = USBD->GINTSTS & USBD->GINTEN; /* get interrupt status */
if (!IrqStL) return;
@ -635,17 +661,25 @@ static void nu_usbd_isr(int vector, void *param)
{
if (USBD_IS_ATTACHED())
{
LOG_I("PLUG IN");
/* USB Plug In */
USBD_ENABLE_USB();
rt_usbd_connect_handler(&_rt_obj_udc);
if (!nu_usbd.plugging_status)
{
LOG_I("PLUG IN");
/* USB Plug In */
nu_udc_enable();
rt_usbd_connect_handler(&_rt_obj_udc);
nu_usbd.plugging_status = 1;
}
}
else
{
LOG_I("Un-Plug");
/* USB Un-plug */
USBD_DISABLE_USB();
rt_usbd_disconnect_handler(&_rt_obj_udc);
if (nu_usbd.plugging_status)
{
LOG_I("Un-Plug");
/* USB Un-plug */
nu_udc_disable();
rt_usbd_disconnect_handler(&_rt_obj_udc);
nu_usbd.plugging_status = 0;
}
}
USBD_CLR_BUS_INT_FLAG(USBD_BUSINTSTS_VBUSDETIF_Msk);
}
@ -791,29 +825,15 @@ static void nu_usbd_isr(int vector, void *param)
static rt_err_t _init(rt_device_t device)
{
#if !defined(BSP_USING_OTG)
uint32_t volatile i;
/* Initialize USB PHY */
SYS_UnlockReg();
SYS->USBPHY &= ~SYS_USBPHY_HSUSBROLE_Msk; /* select USBD */
/* Enable USB PHY */
SYS->USBPHY = (SYS->USBPHY & ~(SYS_USBPHY_HSUSBROLE_Msk | SYS_USBPHY_HSUSBACT_Msk)) | SYS_USBPHY_HSUSBEN_Msk;
for (i = 0; i < 0x1000; i++)
__NOP(); // delay > 10 us
SYS->USBPHY |= SYS_USBPHY_HSUSBACT_Msk;
SYS_LockReg();
#endif
nu_sys_ipclk_enable(nu_usbd.clkidx);
nu_sys_ip_reset(nu_usbd.rstidx);
nu_systick_udelay(1000);
/* USBD Open */
USBD->PHYCTL |= (USBD_PHYCTL_PHYEN_Msk | USBD_PHYCTL_DPPUEN_Msk);
USBD_ENABLE_USB();
while (1)
{
USBD->EP[EPA].EPMPS = 0x20ul;
@ -842,7 +862,11 @@ static rt_err_t _init(rt_device_t device)
rt_hw_interrupt_umask(nu_usbd.irqn);
/* Start transaction */
USBD_Start();
USBD_CLR_SE0();
/* Get currect cable status */
nu_usbd.plugging_status = USBD_IS_ATTACHED() >> USBD_PHYCTL_VBUSDET_Pos;
return RT_EOK;
}

View File

@ -0,0 +1,893 @@
/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-12-30 Wayne First version
*
******************************************************************************/
#include <rtconfig.h>
#if defined(BSP_USING_USBH)
#include <rtdevice.h>
#include <rthw.h>
#include <NuMicro.h>
#include "usb.h"
#include "usbh_lib.h"
#if !defined(NU_USBHOST_HUB_POLLING_INTERVAL)
#define NU_USBHOST_HUB_POLLING_INTERVAL (100)
#endif
#define NU_MAX_USBH_PORT 2 //2* USB2.0 port
#define NU_MAX_USBH_PIPE 16
#define NU_USBH_THREAD_STACK_SIZE 2048
#define NU_MAX_USBH_HUB_PORT_DEV USB_HUB_PORT_NUM
/* Private typedef --------------------------------------------------------------*/
typedef struct nu_port_dev
{
rt_bool_t bRHParent;
UDEV_T *pUDev;
EP_INFO_T *apsEPInfo[NU_MAX_USBH_PIPE];
struct urequest asSetupReq[NU_MAX_USBH_PIPE];
struct rt_completion utr_completion;
int port_num;
rt_bool_t bEnumDone;
#if defined(BSP_USING_MMU)
void *asPipePktBuf[NU_MAX_USBH_PIPE];
#endif
} S_NU_PORT_DEV;
typedef struct nu_port_ctrl
{
S_NU_PORT_DEV sRHPortDev;
S_NU_PORT_DEV asHubPortDev[NU_MAX_USBH_HUB_PORT_DEV];
} S_NU_RH_PORT_CTRL;
struct nu_usbh_dev
{
struct uhcd uhcd;
E_SYS_IPRST rstidx;
E_SYS_IPCLK clkidx;
rt_thread_t polling_thread;
S_NU_RH_PORT_CTRL asPortCtrl[NU_MAX_USBH_PORT];
};
/* Private variables ------------------------------------------------------------*/
static struct nu_usbh_dev s_sUSBHDev =
{
.rstidx = USBHRST,
.clkidx = USBHCKEN,
};
static S_NU_RH_PORT_CTRL *
GetRHPortControlFromPipe(
upipe_t pipe)
{
uinst_t inst;
int port;
if (pipe->inst->parent_hub->is_roothub)
{
//case: device ---> root hub
inst = pipe->inst;
port = inst->port;
}
else
{
//case: device ---> hub ---> root hub
inst = pipe->inst->parent_hub->self;
port = inst->port;
}
if (port > NU_MAX_USBH_PORT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: port index over NU_MAX_USBH_PORT\n"));
return RT_NULL;
}
return &s_sUSBHDev.asPortCtrl[port - 1];;
}
static S_NU_PORT_DEV *
GetPortDevFromPipe(
upipe_t pipe)
{
S_NU_RH_PORT_CTRL *psRHPortCtrl = GetRHPortControlFromPipe(pipe);
int i;
if (psRHPortCtrl == RT_NULL)
return RT_NULL;
if (pipe->inst->parent_hub->is_roothub)
{
//case: device ---> root hub
return &psRHPortCtrl->sRHPortDev;
}
//case: device ---> hub ---> root hub
for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
{
if (psRHPortCtrl->asHubPortDev[i].port_num == pipe->inst->port)
break;
}
if (i >= NU_MAX_USBH_HUB_PORT_DEV)
return RT_NULL;
return &psRHPortCtrl->asHubPortDev[i];
}
static rt_err_t nu_reset_port(rt_uint8_t port)
{
S_NU_RH_PORT_CTRL *psPortCtrl;
if (port > NU_MAX_USBH_PORT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: port index over NU_MAX_USBH_PORT\n", __func__));
return RT_EIO;
}
psPortCtrl = &s_sUSBHDev.asPortCtrl[port - 1];
if (psPortCtrl->sRHPortDev.pUDev == NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
return RT_EIO;
}
usbh_reset_port(psPortCtrl->sRHPortDev.pUDev);
return RT_EOK;
}
static EP_INFO_T *GetFreePipe(
S_NU_RH_PORT_CTRL *psPortCtrl,
S_NU_PORT_DEV *psPortDev,
rt_uint8_t *pu8PipeIndex)
{
if (psPortCtrl != NULL)
{
int i;
/* Find free Pipe */
for (i = 0; i < NU_MAX_USBH_PIPE; i ++)
{
if (psPortDev->apsEPInfo[i] == NULL)
break;
}
if (i < NU_MAX_USBH_PIPE)
{
EP_INFO_T *psEPInfo = rt_malloc(sizeof(EP_INFO_T));
if (psEPInfo != RT_NULL)
{
psPortDev->apsEPInfo[i] = psEPInfo;
*pu8PipeIndex = i;
return psEPInfo;
}
}
}
return RT_NULL;
}
static void FreePipe(
S_NU_RH_PORT_CTRL *psPortCtrl,
S_NU_PORT_DEV *psPortDev,
rt_uint8_t u8PipeIndex)
{
if ((psPortCtrl != RT_NULL) &&
(u8PipeIndex < NU_MAX_USBH_PIPE) &&
(psPortDev->apsEPInfo[u8PipeIndex] != RT_NULL))
{
rt_free(psPortDev->apsEPInfo[u8PipeIndex]);
psPortDev->apsEPInfo[u8PipeIndex] = RT_NULL;
}
}
static S_NU_PORT_DEV *
AllocateNewUDev(
S_NU_RH_PORT_CTRL *psRHPortCtrl)
{
if (psRHPortCtrl != RT_NULL)
{
int i;
/* Find free Dev */
for (i = 0 ; i < NU_MAX_USBH_HUB_PORT_DEV; i ++)
{
if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
break;
}
if (i < NU_MAX_USBH_HUB_PORT_DEV)
{
psRHPortCtrl->asHubPortDev[i].pUDev = alloc_device();
if (psRHPortCtrl->asHubPortDev[i].pUDev == NULL)
{
return RT_NULL;
}
else
{
return &psRHPortCtrl->asHubPortDev[i];
}
}
}
return RT_NULL;
}
static rt_err_t nu_open_pipe(upipe_t pipe)
{
S_NU_RH_PORT_CTRL *psPortCtrl;
S_NU_PORT_DEV *psPortDev;
psPortCtrl = GetRHPortControlFromPipe(pipe);
if (psPortCtrl == RT_NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: RHPort not found\n", __func__));
goto exit_nu_open_pipe;
}
if (psPortCtrl->sRHPortDev.pUDev == NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: udev not found\n", __func__));
goto exit_nu_open_pipe;
}
psPortDev = GetPortDevFromPipe(pipe);
if ((psPortDev == NULL) || (psPortDev->pUDev == NULL))
{
//allocate new dev for hub device
psPortDev = AllocateNewUDev(psPortCtrl);
if (psPortDev == RT_NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_open_pipe ERROR: udev allocate failed\n"));
goto exit_nu_open_pipe;
}
if (pipe->inst->speed)
{
psPortDev->pUDev->speed = SPEED_FULL;
}
else
{
psPortDev->pUDev->speed = SPEED_HIGH;
}
psPortDev->pUDev->parent = NULL;
psPortDev->pUDev->hc_driver = psPortCtrl->sRHPortDev.pUDev->hc_driver;
psPortDev->port_num = pipe->inst->port;
psPortDev->pUDev->port_num = pipe->inst->port;
psPortDev->bEnumDone = FALSE;
}
//For ep0 control transfer
if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
{
pipe->pipe_index = 0;
}
else
{
int pksz;
EP_INFO_T *psEPInfo = GetFreePipe(psPortCtrl, psPortDev, &pipe->pipe_index);
if (psEPInfo == RT_NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%s ERROR: get free pipe failed\n", __func__));
goto exit_nu_open_pipe;
}
psEPInfo->bEndpointAddress = pipe->ep.bEndpointAddress;
psEPInfo->bmAttributes = pipe->ep.bmAttributes;
pksz = pipe->ep.wMaxPacketSize;
pksz = (pksz & 0x07ff) * (1 + ((pksz >> 11) & 3));
psEPInfo->wMaxPacketSize = pksz;
psEPInfo->bInterval = pipe->ep.bInterval;
psEPInfo->hw_pipe = NULL;
psEPInfo->bToggle = 0;
}
#if defined(BSP_USING_MMU)
if (!psPortDev->asPipePktBuf[pipe->pipe_index])
{
psPortDev->asPipePktBuf[pipe->pipe_index] = rt_malloc_align(512ul, CACHE_LINE_SIZE);
RT_ASSERT(psPortDev->asPipePktBuf[pipe->pipe_index] != RT_NULL);
}
#endif
return RT_EOK;
exit_nu_open_pipe:
return -RT_ERROR;
}
static rt_err_t nu_close_pipe(upipe_t pipe)
{
S_NU_RH_PORT_CTRL *psPortCtrl;
S_NU_PORT_DEV *psPortDev;
psPortCtrl = GetRHPortControlFromPipe(pipe);
if (psPortCtrl == RT_NULL)
{
return RT_EIO;
}
psPortDev = GetPortDevFromPipe(pipe);
//For ep0 control transfer
if ((pipe->ep.bEndpointAddress & 0x7F) == 0)
{
if ((psPortDev) && (psPortDev->bRHParent == FALSE) && (psPortDev->bEnumDone == TRUE))
{
if (psPortDev->pUDev)
{
int i;
for (i = 0; i < NU_MAX_USBH_PIPE; i++)
{
if (psPortDev->apsEPInfo[i] != NULL)
{
usbh_quit_xfer(psPortDev->pUDev, psPortDev->apsEPInfo[i]);
}
}
free_device(psPortDev->pUDev);
psPortDev->pUDev = NULL;
}
}
}
if (psPortDev != NULL)
{
#if defined(BSP_USING_MMU)
if (psPortDev->asPipePktBuf[pipe->pipe_index])
{
rt_free_align(psPortDev->asPipePktBuf[pipe->pipe_index]);
psPortDev->asPipePktBuf[pipe->pipe_index] = RT_NULL;
}
#endif
FreePipe(psPortCtrl, psPortDev, pipe->pipe_index);
}
return RT_EOK;
}
static int nu_ctrl_xfer(
S_NU_PORT_DEV *psPortDev,
struct urequest *psSetup,
void *buffer,
int timeouts)
{
uint32_t xfer_len = 0;
int ret;
ret = usbh_ctrl_xfer(psPortDev->pUDev, psSetup->request_type, psSetup->bRequest, psSetup->wValue, psSetup->wIndex, psSetup->wLength, buffer, &xfer_len, timeouts * 10);
if (ret < 0)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer failed %d\n", ret));
return ret;
}
if (xfer_len != psSetup->wLength)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_ctrl_xfer ERROR: xfer length %d %d\n", psSetup->wLength, xfer_len));
}
if ((psSetup->bRequest == USB_REQ_SET_ADDRESS) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV))
psPortDev->pUDev->dev_num = psSetup->wValue;
if ((psSetup->bRequest == USB_REQ_SET_CONFIGURATION) && ((psSetup->request_type & 0x60) == REQ_TYPE_STD_DEV))
{
psPortDev->pUDev->cur_conf = psSetup->wValue;
psPortDev->bEnumDone = TRUE;
}
return xfer_len;
}
static int nu_bulk_xfer(
S_NU_PORT_DEV *psPortDev,
UTR_T *psUTR,
int timeouts)
{
int ret;
ret = usbh_bulk_xfer(psUTR);
if (ret < 0)
return ret;
//wait transfer done
rt_completion_wait(&(psPortDev->utr_completion), timeouts);
return 0;
}
static int nu_int_xfer(
upipe_t pipe,
S_NU_PORT_DEV *psPortDev,
UTR_T *psUTR,
int timeouts)
{
int ret;
int retry = 3;
while (retry > 0)
{
ret = usbh_int_xfer(psUTR);
if (ret == 0)
break;
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_int_xfer ERROR: failed to submit interrupt request\n"));
rt_thread_delay((pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) > 0 ? (pipe->ep.bInterval * RT_TICK_PER_SECOND / 1000) : 1);
retry --;
}
if (ret < 0)
return ret;
return 0;
}
static void xfer_done_cb(UTR_T *psUTR)
{
S_NU_PORT_DEV *psPortDev = (S_NU_PORT_DEV *)psUTR->context;
//transfer done, signal utr_completion
rt_completion_done(&(psPortDev->utr_completion));
}
static void int_xfer_done_cb(UTR_T *psUTR)
{
upipe_t pipe = (upipe_t)psUTR->context;
if (psUTR->status != 0)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("Interrupt xfer failed %d\n", psUTR->status));
goto exit_int_xfer_done_cb;
}
if (pipe->callback != RT_NULL)
{
struct uhost_msg msg;
msg.type = USB_MSG_CALLBACK;
msg.content.cb.function = pipe->callback;
msg.content.cb.context = pipe;
rt_usbh_event_signal(&msg);
}
exit_int_xfer_done_cb:
free_utr(psUTR);
}
static int nu_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts)
{
S_NU_RH_PORT_CTRL *psPortCtrl;
S_NU_PORT_DEV *psPortDev;
UTR_T *psUTR = NULL;
int i32XferLen = -1;
void *buffer_nonch = buffer;
psPortCtrl = GetRHPortControlFromPipe(pipe);
if (psPortCtrl == RT_NULL)
{
goto exit_nu_pipe_xfer;
}
psPortDev = GetPortDevFromPipe(pipe);
if (psPortDev->pUDev == NULL)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: udev not found\n"));
goto exit_nu_pipe_xfer;
}
#if defined(BSP_USING_MMU)
if (buffer_nonch && nbytes)
{
buffer_nonch = psPortDev->asPipePktBuf[pipe->pipe_index];
rt_memcpy(buffer_nonch, buffer, nbytes);
mmu_clean_invalidated_dcache((uint32_t)buffer_nonch, nbytes);
}
#endif
//ctrl xfer
if (pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL)
{
int ret;
if (token == USBH_PID_SETUP)
{
struct urequest *psSetup = (struct urequest *)buffer_nonch;
RT_ASSERT(buffer_nonch != RT_NULL);
/* Read data from USB device. */
if (psSetup->request_type & USB_REQ_TYPE_DIR_IN)
{
//Store setup request
rt_memcpy(&psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], psSetup, sizeof(struct urequest));
}
else
{
/* Write data to USB device. */
//Trigger USBHostLib Ctril_Xfer
ret = nu_ctrl_xfer(psPortDev, psSetup, NULL, timeouts);
if (ret != psSetup->wLength)
goto exit_nu_pipe_xfer;
}
}
else
{
//token == USBH_PID_DATA
if (buffer_nonch && ((pipe->ep.bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN))
{
/* Read data from USB device. */
//Trigger USBHostLib Ctril_Xfer
ret = nu_ctrl_xfer(psPortDev, &psPortCtrl->asHubPortDev->asSetupReq[pipe->pipe_index], buffer_nonch, timeouts);
if (ret != nbytes)
goto exit_nu_pipe_xfer;
}
else
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("%d == USBH_PID_DATA, nil buf-%d \n", token, nbytes));
}
} //else
i32XferLen = nbytes;
goto exit_nu_pipe_xfer;
} // if ( pipe->ep.bmAttributes == USB_EP_ATTR_CONTROL )
else
{
psUTR = alloc_utr(psPortDev->pUDev);
if (!psUTR)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: unable alloc UTR\n"));
goto exit_nu_pipe_xfer;
}
psUTR->ep = psPortDev->apsEPInfo[pipe->pipe_index];
psUTR->buff = buffer_nonch;
psUTR->data_len = nbytes;
psUTR->xfer_len = 0;
psUTR->func = xfer_done_cb;
psUTR->context = psPortDev;
psUTR->bIsTransferDone = 0;
psUTR->status = 0;
//others xfer
rt_completion_init(&(psPortDev->utr_completion));
if (pipe->ep.bmAttributes == USB_EP_ATTR_BULK)
{
if (nu_bulk_xfer(psPortDev, psUTR, timeouts) < 0)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: bulk transfer failed\n"));
goto exit_nu_pipe_xfer;
}
}
else if (pipe->ep.bmAttributes == USB_EP_ATTR_INT)
{
psUTR->func = int_xfer_done_cb;
psUTR->context = pipe;
if (nu_int_xfer(pipe, psPortDev, psUTR, timeouts) < 0)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: int transfer failed\n"));
//goto exit_nu_pipe_xfer;
}
else
{
i32XferLen = nbytes;
}
return i32XferLen;
}
else if (pipe->ep.bmAttributes == USB_EP_ATTR_ISOC)
{
//TODO: ISO transfer
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: isoc transfer not support\n"));
goto exit_nu_pipe_xfer;
}
} //else
if (psUTR->bIsTransferDone == 0)
{
//Timeout
RT_DEBUG_LOG(RT_DEBUG_USB, ("nu_pipe_xfer ERROR: timeout\n"));
pipe->status = UPIPE_STATUS_ERROR;
usbh_quit_utr(psUTR);
}
else
{
// Transfer Done. Get status
if (psUTR->status == 0)
{
pipe->status = UPIPE_STATUS_OK;
}
else if (psUTR->status == USBH_ERR_STALL)
{
pipe->status = UPIPE_STATUS_STALL;
}
else
{
pipe->status = UPIPE_STATUS_ERROR;
}
}
i32XferLen = psUTR->xfer_len;
//Call callback
if (pipe->callback != RT_NULL)
{
struct uhost_msg msg;
msg.type = USB_MSG_CALLBACK;
msg.content.cb.function = pipe->callback;
msg.content.cb.context = pipe->user_data;
rt_usbh_event_signal(&msg);
}
if (pipe->status != UPIPE_STATUS_OK)
goto exit_nu_pipe_xfer;
exit_nu_pipe_xfer:
#if defined(BSP_USING_MMU)
if ((nbytes) &&
(buffer_nonch != buffer))
{
mmu_invalidate_dcache((uint32_t)buffer_nonch, nbytes);
rt_memcpy(buffer, buffer_nonch, nbytes);
}
#endif
if (psUTR)
free_utr(psUTR);
return i32XferLen;
}
/* Polling USB root hub status task */
static void nu_usbh_rh_thread_entry(void *parameter)
{
while (1)
{
usbh_polling_root_hubs();
rt_thread_mdelay(NU_USBHOST_HUB_POLLING_INTERVAL);
}
}
static void nu_hcd_connect_callback(
struct udev_t *udev,
int param)
{
int i;
int port_index;
S_NU_RH_PORT_CTRL *psPortCtrl;
/* Igrone event if role is USBD*/
if (nu_sys_usb0_role() == USB0_ID_HOST)
{
SYS_UnlockReg();
outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) | (1 << 11))); /* Set USRHDSEN as 1; USB host/device role selection decided by USBID (SYS_PWRON[16]) */
outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) | (1 << 16))); /* Set USB port 0 used for Host */
SYS_LockReg();
}
for (i = 0; i < NU_MAX_USBH_PORT; i++)
{
psPortCtrl = &s_sUSBHDev.asPortCtrl[i];
if (psPortCtrl->sRHPortDev.pUDev == NULL)
break;
}
if (i >= NU_MAX_USBH_PORT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: port connect slot is full\n"));
return;
}
port_index = i + 1;
psPortCtrl->sRHPortDev.pUDev = udev;
psPortCtrl->sRHPortDev.bRHParent = TRUE;
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb connected\n"));
if (udev->speed == SPEED_HIGH)
rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_TRUE);
else
rt_usbh_root_hub_connect_handler(&s_sUSBHDev.uhcd, port_index, RT_FALSE);
}
static void nu_hcd_disconnect_callback(
struct udev_t *udev,
int param)
{
int i;
int port_index;
S_NU_RH_PORT_CTRL *psPortCtrl;
for (i = 0; i < NU_MAX_USBH_PORT; i++)
{
psPortCtrl = &s_sUSBHDev.asPortCtrl[i];
if (psPortCtrl->sRHPortDev.pUDev == udev)
break;
}
if (i >= NU_MAX_USBH_PORT)
{
RT_DEBUG_LOG(RT_DEBUG_USB, ("ERROR: udev not found\n"));
return;
}
port_index = i + 1;
for (i = 0; i < NU_MAX_USBH_PIPE; i++)
{
if (psPortCtrl->sRHPortDev.apsEPInfo[i] != NULL)
{
usbh_quit_xfer(psPortCtrl->sRHPortDev.pUDev, psPortCtrl->sRHPortDev.apsEPInfo[i]);
}
}
psPortCtrl->sRHPortDev.pUDev = NULL;
RT_DEBUG_LOG(RT_DEBUG_USB, ("usb disconnect\n"));
rt_usbh_root_hub_disconnect_handler(&s_sUSBHDev.uhcd, port_index);
if (nu_sys_usb0_role() != USB0_ID_HOST)
{
SYS_UnlockReg();
outpw(REG_SYS_MISCFCR, (inpw(REG_SYS_MISCFCR) & (~(1 << 11))));
outpw(REG_SYS_PWRON, (inpw(REG_SYS_PWRON) & (~(1 << 16))));
SYS_LockReg();
}
}
/* USB host operations -----------------------------------------------------------*/
static struct uhcd_ops nu_uhcd_ops =
{
nu_reset_port,
nu_pipe_xfer,
nu_open_pipe,
nu_close_pipe,
};
static rt_err_t nu_hcd_init(rt_device_t device)
{
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
usbh_core_init();
//install connect/disconnect callback
usbh_install_conn_callback(nu_hcd_connect_callback, nu_hcd_disconnect_callback);
usbh_polling_root_hubs();
//create thread for polling usbh port status
/* create usb hub thread */
pNuUSBHDev->polling_thread = rt_thread_create("usbh_drv", nu_usbh_rh_thread_entry, RT_NULL,
NU_USBH_THREAD_STACK_SIZE, 8, 20);
RT_ASSERT(pNuUSBHDev->polling_thread != RT_NULL);
/* startup usb host thread */
rt_thread_startup(pNuUSBHDev->polling_thread);
return RT_EOK;
}
/* global function for USB host library -----------------------------*/
uint32_t usbh_get_ticks(void)
{
return rt_tick_get();
}
void usbh_delay_ms(int msec)
{
rt_thread_mdelay(msec);
}
uint32_t usbh_tick_from_millisecond(uint32_t msec)
{
return rt_tick_from_millisecond(msec);
}
#if defined(RT_USING_PM)
/* device pm suspend() entry. */
static int usbhost_pm_suspend(const struct rt_device *device, rt_uint8_t mode)
{
rt_err_t result;
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
RT_ASSERT(pNuUSBHDev != RT_NULL);
switch (mode)
{
case PM_SLEEP_MODE_LIGHT:
case PM_SLEEP_MODE_DEEP:
pNuUSBHDev->polling_thread->stat = RT_THREAD_READY;
result = rt_thread_suspend(pNuUSBHDev->polling_thread);
RT_ASSERT(result == RT_EOK);
break;
default:
break;
}
return (int)RT_EOK;
}
/* device pm resume() entry. */
static void usbhost_pm_resume(const struct rt_device *device, rt_uint8_t mode)
{
rt_err_t result;
struct nu_usbh_dev *pNuUSBHDev = (struct nu_usbh_dev *)device;
RT_ASSERT(pNuUSBHDev != RT_NULL);
switch (mode)
{
case PM_SLEEP_MODE_LIGHT:
case PM_SLEEP_MODE_DEEP:
result = rt_thread_resume(pNuUSBHDev->polling_thread);
RT_ASSERT(result == RT_EOK);
break;
default:
break;
}
}
static struct rt_device_pm_ops device_pm_ops =
{
.suspend = usbhost_pm_suspend,
.resume = usbhost_pm_resume,
.frequency_change = RT_NULL
};
#endif
int nu_usbh_register(void)
{
rt_err_t res;
uhcd_t psUHCD;
psUHCD = (uhcd_t)&s_sUSBHDev.uhcd;
psUHCD->parent.type = RT_Device_Class_USBHost;
psUHCD->parent.init = nu_hcd_init;
psUHCD->parent.user_data = &s_sUSBHDev;
psUHCD->ops = &nu_uhcd_ops;
psUHCD->num_ports = NU_MAX_USBH_PORT;
res = rt_device_register(&psUHCD->parent, "usbh", RT_DEVICE_FLAG_DEACTIVATE);
RT_ASSERT(res == RT_EOK);
nu_sys_ipclk_enable(s_sUSBHDev.clkidx);
nu_sys_ip_reset(s_sUSBHDev.rstidx);
/*initialize the usb host function */
res = rt_usb_host_init();
RT_ASSERT(res == RT_EOK);
#if defined(RT_USING_PM)
rt_pm_device_register(&psUHCD->parent, &device_pm_ops);
#endif
return 0;
}
INIT_DEVICE_EXPORT(nu_usbh_register);
#endif

View File

@ -125,6 +125,11 @@ CONFIG_RT_DFS_ELM_WORD_ACCESS=y
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
CONFIG_RT_DFS_ELM_USE_LFN_3=y
CONFIG_RT_DFS_ELM_USE_LFN=3
CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y
# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set
CONFIG_RT_DFS_ELM_LFN_UNICODE=0
CONFIG_RT_DFS_ELM_MAX_LFN=255
CONFIG_RT_DFS_ELM_DRIVES=8
CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=4096
@ -133,7 +138,12 @@ CONFIG_RT_DFS_ELM_REENTRANT=y
CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_UFFS is not set
CONFIG_RT_USING_DFS_UFFS=y
# CONFIG_RT_UFFS_ECC_MODE_0 is not set
# CONFIG_RT_UFFS_ECC_MODE_1 is not set
# CONFIG_RT_UFFS_ECC_MODE_2 is not set
CONFIG_RT_UFFS_ECC_MODE_3=y
CONFIG_RT_UFFS_ECC_MODE=3
# CONFIG_RT_USING_DFS_JFFS2 is not set
# CONFIG_RT_USING_DFS_NFS is not set
@ -162,7 +172,8 @@ CONFIG_RT_USING_ADC=y
# CONFIG_RT_USING_DAC is not set
CONFIG_RT_USING_PWM=y
# CONFIG_RT_USING_MTD_NOR is not set
# CONFIG_RT_USING_MTD_NAND is not set
CONFIG_RT_USING_MTD_NAND=y
CONFIG_RT_MTD_NAND_DEBUG=y
# CONFIG_RT_USING_PM is not set
CONFIG_RT_USING_RTC=y
CONFIG_RT_USING_ALARM=y
@ -174,12 +185,7 @@ CONFIG_RTC_NTP_SYNC_PERIOD=3600
CONFIG_RT_USING_SPI=y
CONFIG_RT_USING_QSPI=y
# CONFIG_RT_USING_SPI_MSD is not set
CONFIG_RT_USING_SFUD=y
CONFIG_RT_SFUD_USING_SFDP=y
CONFIG_RT_SFUD_USING_FLASH_INFO_TABLE=y
CONFIG_RT_SFUD_USING_QSPI=y
CONFIG_RT_SFUD_SPI_MAX_HZ=50000000
# CONFIG_RT_DEBUG_SFUD is not set
# CONFIG_RT_USING_SFUD is not set
# CONFIG_RT_USING_ENC28J60 is not set
# CONFIG_RT_USING_SPI_WIFI is not set
CONFIG_RT_USING_WDT=y
@ -222,7 +228,7 @@ CONFIG_RT_HWCRYPTO_USING_RNG=y
#
CONFIG_RT_USING_USB_HOST=y
CONFIG_RT_USBH_MSTORAGE=y
CONFIG_UDISK_MOUNTPOINT="/"
CONFIG_UDISK_MOUNTPOINT="/mnt/udisk"
CONFIG_RT_USING_USB_DEVICE=y
CONFIG_RT_USBD_THREAD_STACK_SZ=4096
CONFIG_USB_VENDOR_ID=0x0FFE
@ -264,6 +270,7 @@ CONFIG_RT_USING_POSIX=y
# Socket abstraction layer
#
CONFIG_RT_USING_SAL=y
CONFIG_SAL_INTERNET_CHECK=y
#
# protocol stack implement
@ -523,21 +530,7 @@ CONFIG_PKG_NETUTILS_VER="v1.2.0"
# CONFIG_PKG_USING_PIXMAN is not set
# CONFIG_PKG_USING_LWEXT4 is not set
# CONFIG_PKG_USING_PARTITION is not set
CONFIG_PKG_USING_FAL=y
CONFIG_PKG_FAL_PATH="/packages/system/fal"
CONFIG_FAL_DEBUG_CONFIG=y
CONFIG_FAL_DEBUG=1
CONFIG_FAL_PART_HAS_TABLE_CFG=y
CONFIG_FAL_USING_SFUD_PORT=y
CONFIG_FAL_USING_NOR_FLASH_DEV_NAME="norflash0"
# CONFIG_PKG_USING_FAL_V00500 is not set
# CONFIG_PKG_USING_FAL_V00400 is not set
# CONFIG_PKG_USING_FAL_V00300 is not set
# CONFIG_PKG_USING_FAL_V00200 is not set
# CONFIG_PKG_USING_FAL_V00100 is not set
CONFIG_PKG_USING_FAL_LATEST_VERSION=y
CONFIG_PKG_FAL_VER="latest"
CONFIG_PKG_FAL_VER_NUM=0x99999
# CONFIG_PKG_USING_FAL is not set
# CONFIG_PKG_USING_FLASHDB is not set
# CONFIG_PKG_USING_SQLITE is not set
# CONFIG_PKG_USING_RTI is not set
@ -707,6 +700,7 @@ CONFIG_NU_PKG_USING_DEMO=y
# CONFIG_NU_PKG_USING_NAU88L25 is not set
CONFIG_NU_PKG_USING_NAU8822=y
# CONFIG_NU_PKG_USING_ILI9341 is not set
CONFIG_NU_PKG_USING_SPINAND=y
#
# Hardware Drivers Config
@ -734,23 +728,18 @@ CONFIG_BSP_USING_TMR=y
CONFIG_BSP_USING_TIMER=y
CONFIG_BSP_USING_TMR0=y
CONFIG_BSP_USING_TIMER0=y
# CONFIG_BSP_USING_TPWM0 is not set
# CONFIG_BSP_USING_TIMER0_CAPTURE is not set
CONFIG_BSP_USING_TMR1=y
CONFIG_BSP_USING_TIMER1=y
# CONFIG_BSP_USING_TPWM1 is not set
# CONFIG_BSP_USING_TIMER1_CAPTURE is not set
CONFIG_BSP_USING_TMR2=y
CONFIG_BSP_USING_TIMER2=y
# CONFIG_BSP_USING_TPWM2 is not set
# CONFIG_BSP_USING_TIMER2_CAPTURE is not set
CONFIG_BSP_USING_TMR3=y
CONFIG_BSP_USING_TIMER3=y
# CONFIG_BSP_USING_TPWM3 is not set
# CONFIG_BSP_USING_TIMER3_CAPTURE is not set
CONFIG_BSP_USING_TMR4=y
CONFIG_BSP_USING_TIMER4=y
# CONFIG_BSP_USING_TPWM4 is not set
# CONFIG_BSP_USING_TIMER4_CAPTURE is not set
CONFIG_BSP_USING_UART=y
CONFIG_BSP_USING_UART0=y
@ -793,7 +782,7 @@ CONFIG_BSP_USING_I2S=y
CONFIG_NU_I2S_DMA_FIFO_SIZE=4096
CONFIG_BSP_USING_QSPI=y
CONFIG_BSP_USING_QSPI0=y
# CONFIG_BSP_USING_QSPI0_PDMA is not set
CONFIG_BSP_USING_QSPI0_PDMA=y
# CONFIG_BSP_USING_SCUART is not set
CONFIG_BSP_USING_CRYPTO=y
# CONFIG_NU_PRNG_USE_SEED is not set
@ -802,7 +791,6 @@ CONFIG_BSP_USING_WDT=y
# CONFIG_BSP_USING_EBI is not set
CONFIG_BSP_USING_USBD=y
CONFIG_BSP_USING_USBH=y
CONFIG_BSP_USING_OTG=y
#
# On-board Peripheral Drivers
@ -811,11 +799,10 @@ CONFIG_BSP_USING_CONSOLE=y
CONFIG_BOARD_USING_IP101GR=y
CONFIG_BOARD_USING_NAU8822=y
CONFIG_BOARD_USING_STORAGE_SDCARD=y
CONFIG_BOARD_USING_STORAGE_SPIFLASH=y
# CONFIG_BOARD_USING_USB_NONE is not set
# CONFIG_BOARD_USING_USB_HOST is not set
# CONFIG_BOARD_USING_USB_OTG is not set
CONFIG_BOARD_USING_USB_OTG_HOST=y
# CONFIG_BOARD_USING_STORAGE_SPIFLASH is not set
CONFIG_BOARD_USING_STORAGE_SPINAND=y
CONFIG_BOARD_USING_USB0_DEVICE_HOST=y
CONFIG_BOARD_USING_USB1_HOST=y
#
# Board extended module drivers

View File

@ -43,8 +43,8 @@ Nuvoton Technology provides industrial IoT development platform using NUC980DK61
|LEDs | | Supported |
|Audio Codec | NAU8822, Supports MIC and earphone | Supported |
|USB Device | VCOM + MStorage | Supported |
|2xUSB Host | MStorage | Not ready |
|SPI NAND flash | W25N01GVZE1G | Not ready |
|2xUSB Host | MStorage | Supported |
|SPI NAND flash | W25N01GVZE1G | Supported |
|VCOM | For console | Ready.(Need to install VCOM driver) |
## 2. Supported compiler
@ -88,6 +88,43 @@ Execute Address: 0x0<br>
Enjoy!! <br>
<br>
### 3.3 SPI NAND flash using NuWriter
You can use NuWriter to program rtthread.bin into SPI NAND flash.
[![SPI NAND flash](https://i.imgur.com/p9LudBK.gif "SPI NAND flash")](https://i.imgur.com/p9LudBK.gif "SPI NAND flash using NuWriter")
<br>
Choose type: SPINAND<br>
<< Press Re-Connect >><br>
<< Press Erase >><br>
<< Select Erase All >><br>
<< Press OK >><br>
Choose file: Specify your uboot-spl.bin file.<br>
Image Type: Loader<br>
Execute Address: 0x200<br>
<< Press Program >><br>
Choose file: Specify your uboot.bin file.<br>
Image Type: Data<br>
Image start address: 0x100000<br>
<< Press Program >><br>
Choose file: Specify your rtthread.bin file.<br>
Image Type: Data<br>
Image start address: 0x200000<br>
<< Press Program >><br>
Choose file: Specify your env.txt file.<br>
Image Type: Environment<br>
Image start address: 0x80000<br>
<< Press Program >><br>
<< Press OK & Wait it down >><br>
<< Set Power-on setting to SPI NAND booting >><br>
<< Press Reset button on board >><br>
Enjoy!! <br>
<br>
## 4. Test
You can use Tera Term terminate emulator (or other software) to type commands of RTT. All parameters of serial communication are shown in below image. Here, you can find out the corresponding port number of Nuvoton Virtual Com Port in window device manager.

View File

@ -22,6 +22,7 @@
/* defined the LED_Y pin: PB8 */
#define LED_Y NU_GET_PININDEX(NU_PB, 8)
#if !defined(BSP_USING_USBH)
/* defined the Key1 pin: PE10 */
#define KEY_1 NU_GET_PININDEX(NU_PE, 10)
@ -47,6 +48,8 @@ void nu_button_cb(void *args)
}
#endif
#endif
int main(int argc, char **argv)
{
#if defined(RT_USING_PIN)
@ -58,6 +61,7 @@ int main(int argc, char **argv)
/* set LED_Y pin mode to output */
rt_pin_mode(LED_Y, PIN_MODE_OUTPUT);
#if !defined(BSP_USING_USBH)
/* set KEY_1 pin mode to input */
rt_pin_mode(KEY_1, PIN_MODE_INPUT_PULLUP);
@ -69,6 +73,7 @@ int main(int argc, char **argv)
rt_pin_attach_irq(KEY_2, PIN_IRQ_MODE_FALLING, nu_button_cb, &u32Key2);
rt_pin_irq_enable(KEY_2, PIN_IRQ_ENABLE);
#endif
while (counter--)
{

View File

@ -53,7 +53,10 @@ const void *data;
const struct dfs_mount_tbl mount_table[] =
{
{ RAMDISK_UDC, "/ramdisk_udc", "elm", 0, RT_NULL },
{ RAMDISK_UDC, "/mnt/ram_usbd", "elm", 0, RT_NULL },
#if defined(RT_USING_DFS_UFFS)
{ "nand1", "/mnt/filesystem", "uffs", 0, RT_NULL },
#endif
{0},
};
#endif
@ -171,10 +174,11 @@ int filesystem_init(void)
LOG_I("ramdisk mounted on \"/\".");
/* now you can create dir dynamically. */
mkdir_p("/ramdisk_udc", 0x777);
mkdir_p("/mnt", 0x777);
mkdir_p("/cache", 0x777);
mkdir_p("/download", 0x777);
mkdir_p("/mnt/ram_usbd", 0x777);
mkdir_p("/mnt/filesystem", 0x777);
#if defined(RT_USBH_MSTORAGE) && defined(UDISK_MOUNTPOINT)
mkdir_p(UDISK_MOUNTPOINT, 0x777);
#endif
@ -219,11 +223,6 @@ int mnt_init_spiflash0(void)
rt_kprintf("Failed to create block device for %s.\n", PARTITION_NAME_FILESYSTEM);
goto exit_mnt_init_spiflash0;
}
else if (mkdir(MOUNT_POINT_SPIFLASH0, 0x777) < 0)
{
rt_kprintf("Failed to make folder for %s.\n", MOUNT_POINT_SPIFLASH0);
goto exit_mnt_init_spiflash0;
}
else if (dfs_mount(psNorFlash->parent.name, MOUNT_POINT_SPIFLASH0, "elm", 0, 0) != 0)
{
rt_kprintf("Failed to mount elm on %s.\n", MOUNT_POINT_SPIFLASH0);

View File

@ -33,39 +33,31 @@ menu "Hardware Drivers Config"
default y
config BOARD_USING_STORAGE_SPIFLASH
bool "SPIFLASH supporting(over qspi0)"
bool "SPI NOR FLASH supporting(over qspi0)"
select BSP_USING_QSPI
select BSP_USING_QSPI0
default n
config BOARD_USING_STORAGE_SPINAND
bool "SPI NAND FLASH supporting(over qspi0)"
select BSP_USING_QSPI
select BSP_USING_QSPI0
select NU_PKG_USING_SPINAND
default y
choice
prompt "Select HS USB Ports"
config BOARD_USING_USB0_DEVICE_HOST
select BSP_USING_USBH
select BSP_USING_USBD
bool "Enable USB0 Device/Host"
help
Choose this option if you need USB device or host function mode.
If you need USB host, please remember short to ground on JP1 jumper.
config BOARD_USING_USB_NONE
bool "Without any USB function"
help
Choose this option if you need not USB functions.
config BOARD_USING_USB_HOST
select BSP_USING_USBH
bool "Enable USBH"
help
Choose this option if you need USB HOST function mode.
config BOARD_USING_USB_OTG
select BSP_USING_OTG
bool "Enable OTG"
help
Choose this option if you need USB HOST function mode.
config BOARD_USING_USB_OTG_HOST
select BSP_USING_USBH
select BSP_USING_OTG
bool "Enable OTG AND USBH"
help
Choose this option if you need both USB ports function mode.
endchoice
config BOARD_USING_USB1_HOST
select BSP_USING_USBH
bool "Enable USB1 Host"
help
Choose this option if you need USB1 HOST.
endmenu

Some files were not shown because too many files have changed in this diff Show More