You've already forked dspico-usb-examples
mirror of
https://github.com/LNH-team/dspico-usb-examples.git
synced 2026-01-09 16:27:56 -08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
651084bb75 | ||
|
|
3919db5ec3 | ||
|
|
ac2fdd440b | ||
|
|
b51ef2a722 | ||
|
|
d076041fdf |
39
.github/workflows/build.yml
vendored
Normal file
39
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Build USB examples
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["develop"]
|
||||||
|
paths-ignore:
|
||||||
|
- 'README.md'
|
||||||
|
pull_request:
|
||||||
|
branches: ["develop"]
|
||||||
|
paths-ignore:
|
||||||
|
- 'README.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
example: [
|
||||||
|
"mass-storage",
|
||||||
|
"usb-microphone",
|
||||||
|
"usb-speaker",
|
||||||
|
"usb-video"
|
||||||
|
]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: devkitpro/devkitarm:20241104
|
||||||
|
name: Build with Docker using devkitARM
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Build example
|
||||||
|
run: |
|
||||||
|
cd examples/${{ matrix.example }}
|
||||||
|
make
|
||||||
|
- name: Publish build to GH Actions
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: examples/${{ matrix.example }}/${{ matrix.example }}.nds
|
||||||
|
name: ${{ matrix.example }}
|
||||||
38
.github/workflows/release.yml
vendored
Normal file
38
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Build USB examples release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
example: [
|
||||||
|
"mass-storage",
|
||||||
|
"usb-microphone",
|
||||||
|
"usb-speaker",
|
||||||
|
"usb-video"
|
||||||
|
]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: devkitpro/devkitarm:20241104
|
||||||
|
name: Build with Docker using devkitARM
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- name: Build example
|
||||||
|
run: |
|
||||||
|
cd examples/${{ matrix.example }}
|
||||||
|
make
|
||||||
|
- name: Publish build to GH Actions
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: examples/${{ matrix.example }}/${{ matrix.example }}.nds
|
||||||
|
name: ${{ matrix.example }}
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
examples/${{ matrix.example }}/${{ matrix.example }}.nds
|
||||||
@@ -3,6 +3,8 @@ This repository contains examples of using the DSpico USB port from a DS applica
|
|||||||
|
|
||||||
The `examples` folder contains the following examples:
|
The `examples` folder contains the following examples:
|
||||||
- mass-storage - Allows access to the DSpico micro SD card over USB
|
- mass-storage - Allows access to the DSpico micro SD card over USB
|
||||||
|
- usb-microphone - Makes the DSi/3DS work as a USB microphone for your PC
|
||||||
|
- Note: does not work with regular DS devices currently
|
||||||
- usb-speaker - Makes the DS/DSi/3DS work as a USB speaker for your PC
|
- usb-speaker - Makes the DS/DSi/3DS work as a USB speaker for your PC
|
||||||
- usb-video - Allows to use the camera of your DSi or 3DS on your PC via USB
|
- usb-video - Allows to use the camera of your DSi or 3DS on your PC via USB
|
||||||
|
|
||||||
|
|||||||
61
examples/usb-microphone/Makefile
Normal file
61
examples/usb-microphone/Makefile
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
export TARGET := $(shell basename $(CURDIR))
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
|
||||||
|
# specify a directory which contains the nitro filesystem
|
||||||
|
# this is relative to the Makefile
|
||||||
|
NITRO_FILES :=
|
||||||
|
|
||||||
|
# These set the information text in the nds file
|
||||||
|
GAME_TITLE := USB Microphone Example
|
||||||
|
GAME_SUBTITLE1 := DSpico
|
||||||
|
GAME_SUBTITLE2 := LNH team
|
||||||
|
GAME_ICON := icon.bmp
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
.PHONY: checklibtwl checkarm7 checkarm9 clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: checklibtwl checkarm7 checkarm9 $(TARGET).nds
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
checklibtwl:
|
||||||
|
$(MAKE) -C ../../libs/libtwl/libtwl7
|
||||||
|
$(MAKE) -C ../../libs/libtwl/libtwl9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
checkarm7: checklibtwl
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
checkarm9: checklibtwl
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).nds : $(NITRO_FILES) arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||||
|
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf \
|
||||||
|
-b $(GAME_ICON) "$(GAME_TITLE);$(GAME_SUBTITLE1);$(GAME_SUBTITLE2)" \
|
||||||
|
$(_ADDFILES)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm7/$(TARGET).elf:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm9/$(TARGET).elf:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C arm9 clean
|
||||||
|
$(MAKE) -C arm7 clean
|
||||||
|
rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9
|
||||||
137
examples/usb-microphone/arm7/Makefile
Normal file
137
examples/usb-microphone/arm7/Makefile
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source \
|
||||||
|
../common/ipc \
|
||||||
|
source/ipcServices \
|
||||||
|
../../../platform \
|
||||||
|
../../../libs/tinyusb/src \
|
||||||
|
../../../libs/tinyusb/src/device \
|
||||||
|
../../../libs/tinyusb/src/class/audio \
|
||||||
|
../../../libs/tinyusb/src/class/cdc \
|
||||||
|
../../../libs/tinyusb/src/class/msc \
|
||||||
|
../../../libs/tinyusb/src/common
|
||||||
|
INCLUDES := source include build ../common ../../../libs/tinyusb/src ../../../platform
|
||||||
|
DATA :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -marm -mthumb-interwork -DLIBTWL_ARM7 -DARM7
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2\
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||||
|
-ffunction-sections -fdata-sections\
|
||||||
|
-ffast-math \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=gnu++23 -Wno-volatile -fno-rtti -fno-exceptions -fno-threadsafe-statics\
|
||||||
|
-Wsuggest-override -Werror=suggest-override
|
||||||
|
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=../dldi_ds_arm7.specs -g $(ARCH) -Wl,--nmagic -Wl,-Map,$(notdir $*).map,--gc-sections -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
|
LIBS := -ltwl7 -lnds7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS) $(CURDIR)/../../../libs/libtwl/libtwl7 $(CURDIR)/../../../libs/libtwl/common
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export ARM7ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM7ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
232
examples/usb-microphone/arm7/dldi_ds_arm7.ld
Normal file
232
examples/usb-microphone/arm7/dldi_ds_arm7.ld
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
--------------------------------------------------------------------------------*/
|
||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
|
||||||
|
PHDRS {
|
||||||
|
crt0 PT_LOAD FLAGS(7);
|
||||||
|
arm7 PT_LOAD FLAGS(7);
|
||||||
|
arm7i PT_LOAD FLAGS(0x100007);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MEMORY {
|
||||||
|
ewram : ORIGIN = 0x02380000, LENGTH = 12M - 512K
|
||||||
|
rom : ORIGIN = 0x08000000, LENGTH = 32M
|
||||||
|
iwram : ORIGIN = 0x037fc000, LENGTH = (96K - 16K)
|
||||||
|
|
||||||
|
twl_ewram : ORIGIN = 0x02e80000, LENGTH = 512K - 64K
|
||||||
|
twl_iwram : ORIGIN = 0x03000000, LENGTH = 256K
|
||||||
|
}
|
||||||
|
|
||||||
|
__iwram_start = ORIGIN(iwram);
|
||||||
|
__iwram_top = ORIGIN(iwram)+ LENGTH(iwram);
|
||||||
|
|
||||||
|
__sp_irq = __iwram_top - 0x100;
|
||||||
|
__sp_svc = __sp_irq - 0x100;
|
||||||
|
__sp_usr = __sp_svc - 0x100;
|
||||||
|
|
||||||
|
__irq_flags = 0x04000000 - 8;
|
||||||
|
__irq_flagsaux = 0x04000000 - 0x40;
|
||||||
|
__irq_vector = 0x04000000 - 4;
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
|
||||||
|
.twl :
|
||||||
|
{
|
||||||
|
__arm7i_lma__ = LOADADDR(.twl);
|
||||||
|
__arm7i_start__ = .;
|
||||||
|
*(.twl)
|
||||||
|
*.twl*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
*.twl*(.rodata)
|
||||||
|
*.twl*(.roda)
|
||||||
|
*.twl*(.rodata.*)
|
||||||
|
*.twl*(.data)
|
||||||
|
*.twl*(.data.*)
|
||||||
|
*.twl*(.gnu.linkonce.d*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__arm7i_end__ = .;
|
||||||
|
} >twl_iwram AT>twl_ewram :arm7i
|
||||||
|
|
||||||
|
.twl_bss ALIGN(4) (NOLOAD) :
|
||||||
|
{
|
||||||
|
__twl_bss_start__ = .;
|
||||||
|
*(.twl_bss)
|
||||||
|
*.twl.*(.dynbss)
|
||||||
|
*.twl.*(.gnu.linkonce.b*)
|
||||||
|
*.twl.*(.bss*)
|
||||||
|
*.twl.*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__twl_bss_end__ = .;
|
||||||
|
} >twl_iwram :NONE
|
||||||
|
|
||||||
|
.crt0 :
|
||||||
|
{
|
||||||
|
KEEP (*(.crt0))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >ewram :crt0
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
__arm7_lma__ = LOADADDR(.text);
|
||||||
|
__arm7_start__ = .;
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
*(.plt)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
KEEP (*(.text.*personality*))
|
||||||
|
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram :arm7
|
||||||
|
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(.fini))
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
*all.rodata*(*)
|
||||||
|
*(.roda)
|
||||||
|
*(.rodata.*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >iwram AT>ewram
|
||||||
|
|
||||||
|
.ARM.exidx : {
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
/* Ensure the __preinit_array_start label is properly aligned. We
|
||||||
|
could instead move the label definition inside the section, but
|
||||||
|
the linker would then create the section even if it turns out to
|
||||||
|
be empty, which isn't pretty. */
|
||||||
|
.preinit_array : {
|
||||||
|
. = ALIGN(32 / 8);
|
||||||
|
PROVIDE (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE (__preinit_array_end = .);
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.init_array : {
|
||||||
|
PROVIDE (__init_array_start = .);
|
||||||
|
KEEP (*(.init_array))
|
||||||
|
PROVIDE (__init_array_end = .);
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.fini_array : {
|
||||||
|
PROVIDE (__fini_array_start = .);
|
||||||
|
KEEP (*(.fini_array))
|
||||||
|
PROVIDE (__fini_array_end = .);
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of the constructors, so
|
||||||
|
we make sure it is first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not actually link against
|
||||||
|
crtbegin.o; the linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it doesn't matter which
|
||||||
|
directory crtbegin.o is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.eh_frame :
|
||||||
|
{
|
||||||
|
KEEP (*(.eh_frame))
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.gcc_except_table :
|
||||||
|
{
|
||||||
|
*(.gcc_except_table)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
} >iwram AT>ewram
|
||||||
|
.jcr : { KEEP (*(.jcr)) } >iwram AT>ewram
|
||||||
|
.got : { *(.got.plt) *(.got) } >iwram AT>ewram
|
||||||
|
|
||||||
|
.data ALIGN(4) : {
|
||||||
|
__data_start = ABSOLUTE(.);
|
||||||
|
*(.data)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
CONSTRUCTORS
|
||||||
|
. = ALIGN(4);
|
||||||
|
__data_end = ABSOLUTE(.) ;
|
||||||
|
} >iwram AT>ewram
|
||||||
|
|
||||||
|
.bss ALIGN(4) (NOLOAD) :
|
||||||
|
{
|
||||||
|
__arm7_end__ = .;
|
||||||
|
__bss_start = ABSOLUTE(.);
|
||||||
|
__bss_start__ = ABSOLUTE(.);
|
||||||
|
*(.dynbss)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
|
||||||
|
__bss_end__ = ABSOLUTE(.);
|
||||||
|
__end__ = ABSOLUTE(.);
|
||||||
|
} >iwram
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* These must appear regardless of . */
|
||||||
|
}
|
||||||
8
examples/usb-microphone/arm7/dldi_ds_arm7.specs
Normal file
8
examples/usb-microphone/arm7/dldi_ds_arm7.specs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T ../dldi_ds_arm7.ld%s --gc-sections --no-warn-rwx-segments
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
ds_arm7_crt0%O%s crti%O%s crtbegin%O%s
|
||||||
|
|
||||||
8
examples/usb-microphone/arm7/source/Arm7State.h
Normal file
8
examples/usb-microphone/arm7/source/Arm7State.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Enum representing the arm7 state.
|
||||||
|
enum class Arm7State
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
ExitRequested
|
||||||
|
};
|
||||||
10
examples/usb-microphone/arm7/source/ExitMode.h
Normal file
10
examples/usb-microphone/arm7/source/ExitMode.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/// @brief Enum representing the exit mode of launcher.
|
||||||
|
enum class ExitMode
|
||||||
|
{
|
||||||
|
/// @brief Reset the system (DSi mode only).
|
||||||
|
Reset,
|
||||||
|
/// @brief Power off the system.
|
||||||
|
PowerOff
|
||||||
|
};
|
||||||
5
examples/usb-microphone/arm7/source/common.h
Normal file
5
examples/usb-microphone/arm7/source/common.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <nds.h>
|
||||||
|
#include <libtwl/rtos/rtosMutex.h>
|
||||||
|
|
||||||
|
extern rtos_mutex_t gCardMutex;
|
||||||
197
examples/usb-microphone/arm7/source/main.cpp
Normal file
197
examples/usb-microphone/arm7/source/main.cpp
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include <libtwl/rtos/rtosIrq.h>
|
||||||
|
#include <libtwl/rtos/rtosThread.h>
|
||||||
|
#include <libtwl/rtos/rtosEvent.h>
|
||||||
|
#include <libtwl/sound/soundChannel.h>
|
||||||
|
#include <libtwl/timer/timer.h>
|
||||||
|
#include <libtwl/sound/sound.h>
|
||||||
|
#include <libtwl/ipc/ipcSync.h>
|
||||||
|
#include <libtwl/ipc/ipcFifoSystem.h>
|
||||||
|
#include <libtwl/sys/sysPower.h>
|
||||||
|
#include <libtwl/sio/sioRtc.h>
|
||||||
|
#include <libtwl/sio/sio.h>
|
||||||
|
#include <libtwl/gfx/gfxStatus.h>
|
||||||
|
#include <libtwl/mem/memSwap.h>
|
||||||
|
#include <libtwl/i2c/i2cMcu.h>
|
||||||
|
#include <libtwl/spi/spiPmic.h>
|
||||||
|
#include "ExitMode.h"
|
||||||
|
#include "Arm7State.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
#include "microphone.h"
|
||||||
|
|
||||||
|
rtos_mutex_t gCardMutex;
|
||||||
|
|
||||||
|
static rtos_thread_t sUsbThread;
|
||||||
|
static u32 sUsbThreadStack[512];
|
||||||
|
|
||||||
|
static rtos_event_t sVBlankEvent;
|
||||||
|
static ExitMode sExitMode;
|
||||||
|
static Arm7State sState;
|
||||||
|
static volatile u8 sMcuIrqFlag = false;
|
||||||
|
|
||||||
|
static void vblankIrq(u32 irqMask)
|
||||||
|
{
|
||||||
|
rtos_signalEvent(&sVBlankEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mcuIrq(u32 irq2Mask)
|
||||||
|
{
|
||||||
|
sMcuIrqFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void checkMcuIrq(void)
|
||||||
|
{
|
||||||
|
// mcu only exists in DSi mode
|
||||||
|
if (isDSiMode())
|
||||||
|
{
|
||||||
|
// check and ack the flag atomically
|
||||||
|
if (mem_swapByte(false, &sMcuIrqFlag))
|
||||||
|
{
|
||||||
|
// check the irq mask
|
||||||
|
u32 irqMask = mcu_getIrqMask();
|
||||||
|
if (irqMask & MCU_IRQ_RESET)
|
||||||
|
{
|
||||||
|
// power button was released
|
||||||
|
sExitMode = ExitMode::Reset;
|
||||||
|
sState = Arm7State::ExitRequested;
|
||||||
|
}
|
||||||
|
else if (irqMask & MCU_IRQ_POWER_OFF)
|
||||||
|
{
|
||||||
|
// power button was held long to trigger a power off
|
||||||
|
sExitMode = ExitMode::PowerOff;
|
||||||
|
sState = Arm7State::ExitRequested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initializeVBlankIrq()
|
||||||
|
{
|
||||||
|
rtos_createEvent(&sVBlankEvent);
|
||||||
|
rtos_setIrqFunc(RTOS_IRQ_VBLANK, vblankIrq);
|
||||||
|
rtos_enableIrqMask(RTOS_IRQ_VBLANK);
|
||||||
|
gfx_setVBlankIrqEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usbThreadMain(void* arg)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initializeArm7()
|
||||||
|
{
|
||||||
|
rtos_initIrq();
|
||||||
|
rtos_startMainThread();
|
||||||
|
ipc_initFifoSystem();
|
||||||
|
|
||||||
|
// clear sound registers
|
||||||
|
dmaFillWords(0, (void*)0x04000400, 0x100);
|
||||||
|
|
||||||
|
pmic_setAmplifierEnable(true);
|
||||||
|
sys_setSoundPower(true);
|
||||||
|
|
||||||
|
readUserSettings();
|
||||||
|
pmic_setPowerLedBlink(PMIC_CONTROL_POWER_LED_BLINK_NONE);
|
||||||
|
|
||||||
|
sio_setGpioSiIrq(false);
|
||||||
|
sio_setGpioMode(RCNT0_L_MODE_GPIO);
|
||||||
|
|
||||||
|
rtc_init();
|
||||||
|
|
||||||
|
snd_setMasterVolume(0);
|
||||||
|
snd_setMasterEnable(false);
|
||||||
|
|
||||||
|
initializeVBlankIrq();
|
||||||
|
|
||||||
|
if (isDSiMode())
|
||||||
|
{
|
||||||
|
rtos_setIrq2Func(RTOS_IRQ2_MCU, mcuIrq);
|
||||||
|
rtos_enableIrq2Mask(RTOS_IRQ2_MCU);
|
||||||
|
mic_initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
pmic_setTopBacklightEnable(false);
|
||||||
|
pmic_setBottomBacklightEnable(false);
|
||||||
|
|
||||||
|
tusb_rhport_init_t dev_init =
|
||||||
|
{
|
||||||
|
.role = TUSB_ROLE_DEVICE,
|
||||||
|
.speed = TUSB_SPEED_AUTO
|
||||||
|
};
|
||||||
|
tusb_init(0, &dev_init);
|
||||||
|
|
||||||
|
rtos_createThread(&sUsbThread, 3, usbThreadMain, NULL, sUsbThreadStack, sizeof(sUsbThreadStack));
|
||||||
|
rtos_wakeupThread(&sUsbThread);
|
||||||
|
|
||||||
|
ipc_setArm7SyncBits(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateArm7IdleState()
|
||||||
|
{
|
||||||
|
checkMcuIrq();
|
||||||
|
|
||||||
|
if (sState == Arm7State::ExitRequested)
|
||||||
|
{
|
||||||
|
snd_setMasterVolume(0); // mute sound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool performExit(ExitMode exitMode)
|
||||||
|
{
|
||||||
|
switch (exitMode)
|
||||||
|
{
|
||||||
|
case ExitMode::Reset:
|
||||||
|
{
|
||||||
|
mcu_setWarmBootFlag(true);
|
||||||
|
mcu_hardReset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ExitMode::PowerOff:
|
||||||
|
{
|
||||||
|
pmic_shutdown();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true); // wait infinitely for exit
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateArm7ExitRequestedState()
|
||||||
|
{
|
||||||
|
performExit(sExitMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateArm7()
|
||||||
|
{
|
||||||
|
switch (sState)
|
||||||
|
{
|
||||||
|
case Arm7State::Idle:
|
||||||
|
{
|
||||||
|
updateArm7IdleState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Arm7State::ExitRequested:
|
||||||
|
{
|
||||||
|
updateArm7ExitRequestedState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
sState = Arm7State::Idle;
|
||||||
|
initializeArm7();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
rtos_waitEvent(&sVBlankEvent, true, true);
|
||||||
|
updateArm7();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
282
examples/usb-microphone/arm7/source/microphone.cpp
Normal file
282
examples/usb-microphone/arm7/source/microphone.cpp
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include <libtwl/rtos/rtosIrq.h>
|
||||||
|
#include <libtwl/spi/spiCodec.h>
|
||||||
|
#include <libtwl/sound/twlMicrophone.h>
|
||||||
|
#include <libtwl/sound/twlI2s.h>
|
||||||
|
#include <libtwl/sys/swi.h>
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
#include "microphone.h"
|
||||||
|
|
||||||
|
#define AUDIO_BLOCK_SIZE_IN_BYTES 32
|
||||||
|
#define NUMBER_OF_AUDIO_BUFFERS 128
|
||||||
|
|
||||||
|
static s16 sAudioBuffer[NUMBER_OF_AUDIO_BUFFERS][16];
|
||||||
|
static volatile int sReadBlock;
|
||||||
|
static volatile int sWriteBlock;
|
||||||
|
|
||||||
|
static bool sCaptureStarted = false;
|
||||||
|
static int sOffset = 0;
|
||||||
|
|
||||||
|
static bool sChannelMute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
|
||||||
|
static uint16_t sChannelVolume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
|
||||||
|
|
||||||
|
void mic_initialize()
|
||||||
|
{
|
||||||
|
twlmic_stop();
|
||||||
|
REG_I2SCNT = I2SCNT_MIX_RATIO_DSP_0_NITRO_8 | I2SCNT_FREQUENCY_32728_HZ;
|
||||||
|
codec_setPage(CODEC_PAGE_0);
|
||||||
|
{
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_DAC_NDAC_VAL, 0x87);
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_ADC_NADC_VAL, 0x87);
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_PLL_J, 21);
|
||||||
|
}
|
||||||
|
REG_I2SCNT |= I2SCNT_ENABLE;
|
||||||
|
codec_setPage(CODEC_PAGE_1);
|
||||||
|
{
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE1_MICBIAS, 3);
|
||||||
|
}
|
||||||
|
bool adcOn, dacOn;
|
||||||
|
codec_setPage(CODEC_PAGE_0);
|
||||||
|
{
|
||||||
|
adcOn = codec_readRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC) & 0x80;
|
||||||
|
dacOn = codec_readRegister(CODEC_REG_PAGE0_DAC_DATA_PATH_SETUP) & 0xC0;
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_MIC, 0x80);
|
||||||
|
if (!adcOn || !dacOn)
|
||||||
|
{
|
||||||
|
swi_waitByLoop(0x28E91F); // 20ms
|
||||||
|
}
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_ADC_DIGITAL_VOLUME_CONTROL_FINE_ADJUST, 0);
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE0_AGC_CONTROL_1, 0);
|
||||||
|
}
|
||||||
|
codec_setPage(CODEC_PAGE_1);
|
||||||
|
{
|
||||||
|
sChannelVolume[0] = 40; // dB
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE1_MIC_PGA, sChannelVolume[0] * 2); // gain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void micIrq(u32 irq2Mask)
|
||||||
|
{
|
||||||
|
u32 data[8];
|
||||||
|
data[0] = REG_MIC_FIFO;
|
||||||
|
data[1] = REG_MIC_FIFO;
|
||||||
|
data[2] = REG_MIC_FIFO;
|
||||||
|
data[3] = REG_MIC_FIFO;
|
||||||
|
data[4] = REG_MIC_FIFO;
|
||||||
|
data[5] = REG_MIC_FIFO;
|
||||||
|
data[6] = REG_MIC_FIFO;
|
||||||
|
data[7] = REG_MIC_FIFO;
|
||||||
|
int writeBlock = sWriteBlock;
|
||||||
|
int nextWriteBlock = (writeBlock + 1) % NUMBER_OF_AUDIO_BUFFERS;
|
||||||
|
if (nextWriteBlock != sReadBlock)
|
||||||
|
{
|
||||||
|
memcpy(&sAudioBuffer[writeBlock][0], data, sizeof(data));
|
||||||
|
sWriteBlock = nextWriteBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startMicrophoneCapture()
|
||||||
|
{
|
||||||
|
sReadBlock = 0;
|
||||||
|
sWriteBlock = 0;
|
||||||
|
sOffset = 0;
|
||||||
|
twlmic_stop();
|
||||||
|
twlmic_configure(MICCNT_FORMAT_NORMAL, MICCNT_RATE_DIV_1, MICCNT_IRQ_HALF_OVERFLOW);
|
||||||
|
twlmic_clearFifo();
|
||||||
|
rtos_setIrq2Func(RTOS_IRQ2_MIC, micIrq);
|
||||||
|
rtos_ackIrq2Mask(RTOS_IRQ2_MIC);
|
||||||
|
rtos_enableIrq2Mask(RTOS_IRQ2_MIC);
|
||||||
|
twlmic_start();
|
||||||
|
sCaptureStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopMicrophoneCapture()
|
||||||
|
{
|
||||||
|
rtos_disableIrq2Mask(RTOS_IRQ2_MIC);
|
||||||
|
twlmic_stop();
|
||||||
|
rtos_ackIrq2Mask(RTOS_IRQ2_MIC);
|
||||||
|
sCaptureStarted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handleMicInputTerminalGetRequest(u8 rhport, const tusb_control_request_t* p_request)
|
||||||
|
{
|
||||||
|
u8 ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||||
|
switch (ctrlSel)
|
||||||
|
{
|
||||||
|
case AUDIO_TE_CTRL_CONNECTOR: // Get terminal connector
|
||||||
|
{
|
||||||
|
audio_desc_channel_cluster_t ret;
|
||||||
|
ret.bNrChannels = 1;
|
||||||
|
ret.bmChannelConfig = (audio_channel_config_t)0;
|
||||||
|
ret.iChannelNames = 0;
|
||||||
|
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handleFeatureUnitGetRequest(u8 rhport, const tusb_control_request_t* p_request)
|
||||||
|
{
|
||||||
|
u8 channelNum = TU_U16_LOW(p_request->wValue);
|
||||||
|
u8 ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||||
|
switch (ctrlSel)
|
||||||
|
{
|
||||||
|
case AUDIO_FU_CTRL_MUTE: // Get Mute of channel
|
||||||
|
{
|
||||||
|
return tud_control_xfer(rhport, p_request, &sChannelMute[channelNum], 1);
|
||||||
|
}
|
||||||
|
case AUDIO_FU_CTRL_VOLUME:
|
||||||
|
{
|
||||||
|
switch (p_request->bRequest)
|
||||||
|
{
|
||||||
|
case AUDIO_CS_REQ_CUR: // Get Volume of channel
|
||||||
|
{
|
||||||
|
return tud_control_xfer(rhport, p_request, &sChannelVolume[channelNum], sizeof(sChannelVolume[channelNum]));
|
||||||
|
}
|
||||||
|
case AUDIO_CS_REQ_RANGE: // Get Volume range of channel
|
||||||
|
{
|
||||||
|
audio_control_range_2_n_t(1) ret;
|
||||||
|
ret.wNumSubRanges = 1;
|
||||||
|
ret.subrange[0].bMin = 0; // 0 dB
|
||||||
|
ret.subrange[0].bMax = 59; // +59 dB
|
||||||
|
ret.subrange[0].bRes = 1; // 1 dB steps
|
||||||
|
return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*) &ret, sizeof(ret));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handleFeatureUnitSetRequest(u8 rhport, const tusb_control_request_t* p_request, u8* pBuff)
|
||||||
|
{
|
||||||
|
u8 channelNum = TU_U16_LOW(p_request->wValue);
|
||||||
|
u8 ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||||
|
switch (ctrlSel)
|
||||||
|
{
|
||||||
|
case AUDIO_FU_CTRL_MUTE: // Set Mute of channel
|
||||||
|
{
|
||||||
|
sChannelMute[channelNum] = ((audio_control_cur_1_t*)pBuff)->bCur;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case AUDIO_FU_CTRL_VOLUME: // Set Volume of channel
|
||||||
|
{
|
||||||
|
// Request uses format layout 2
|
||||||
|
sChannelVolume[channelNum] = (uint16_t) ((audio_control_cur_2_t*)pBuff)->bCur;
|
||||||
|
codec_setPage(CODEC_PAGE_1);
|
||||||
|
{
|
||||||
|
codec_writeRegister(CODEC_REG_PAGE1_MIC_PGA, sChannelVolume[channelNum] * 2); // gain
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool handleClockGetRequest(u8 rhport, const tusb_control_request_t* p_request)
|
||||||
|
{
|
||||||
|
u8 ctrlSel = TU_U16_HIGH(p_request->wValue);
|
||||||
|
switch (ctrlSel)
|
||||||
|
{
|
||||||
|
case AUDIO_CS_CTRL_SAM_FREQ:
|
||||||
|
{
|
||||||
|
switch (p_request->bRequest)
|
||||||
|
{
|
||||||
|
case AUDIO_CS_REQ_CUR: // Get Sample Freq.
|
||||||
|
{
|
||||||
|
uint32_t sampFreq = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE;
|
||||||
|
return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
|
||||||
|
}
|
||||||
|
case AUDIO_CS_REQ_RANGE: // Get Sample Freq. range
|
||||||
|
{
|
||||||
|
audio_control_range_4_n_t(1) sampleFreqRng;
|
||||||
|
sampleFreqRng.wNumSubRanges = 1;
|
||||||
|
sampleFreqRng.subrange[0].bMin = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE;
|
||||||
|
sampleFreqRng.subrange[0].bMax = CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE;
|
||||||
|
sampleFreqRng.subrange[0].bRes = 0;
|
||||||
|
return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AUDIO_CS_CTRL_CLK_VALID: // Get Sample Freq. valid
|
||||||
|
{
|
||||||
|
uint8_t clkValid = 1;
|
||||||
|
return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when audio class specific get request received for an entity
|
||||||
|
bool tud_audio_get_req_entity_cb(u8 rhport, const tusb_control_request_t* p_request)
|
||||||
|
{
|
||||||
|
u8 entityId = TU_U16_HIGH(p_request->wIndex);
|
||||||
|
switch (entityId)
|
||||||
|
{
|
||||||
|
case UAC2_ENTITY_MIC_INPUT_TERMINAL:
|
||||||
|
{
|
||||||
|
return handleMicInputTerminalGetRequest(rhport, p_request);
|
||||||
|
}
|
||||||
|
case UAC2_ENTITY_FEATURE_UNIT:
|
||||||
|
{
|
||||||
|
return handleFeatureUnitGetRequest(rhport, p_request);
|
||||||
|
}
|
||||||
|
case UAC2_ENTITY_CLOCK:
|
||||||
|
{
|
||||||
|
return handleClockGetRequest(rhport, p_request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when audio class specific set request received for an entity
|
||||||
|
bool tud_audio_set_req_entity_cb(u8 rhport, const tusb_control_request_t* p_request, u8* pBuff)
|
||||||
|
{
|
||||||
|
u8 entityId = TU_U16_HIGH(p_request->wIndex);
|
||||||
|
switch (entityId)
|
||||||
|
{
|
||||||
|
case UAC2_ENTITY_FEATURE_UNIT:
|
||||||
|
{
|
||||||
|
return handleFeatureUnitSetRequest(rhport, p_request, pBuff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tud_audio_tx_done_pre_load_cb(u8 rhport, u8 itf, u8 ep_in, u8 cur_alt_setting)
|
||||||
|
{
|
||||||
|
if (!sCaptureStarted)
|
||||||
|
{
|
||||||
|
startMicrophoneCapture();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (sReadBlock != sWriteBlock)
|
||||||
|
{
|
||||||
|
int bytesWritten = tud_audio_write(((u8*)&sAudioBuffer[sReadBlock][0]) + sOffset, AUDIO_BLOCK_SIZE_IN_BYTES - sOffset);
|
||||||
|
int offset = AUDIO_BLOCK_SIZE_IN_BYTES - bytesWritten;
|
||||||
|
sOffset = offset % AUDIO_BLOCK_SIZE_IN_BYTES;
|
||||||
|
if (offset > 0)
|
||||||
|
{
|
||||||
|
// Could not write entire block
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sReadBlock = (sReadBlock + 1) % NUMBER_OF_AUDIO_BUFFERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tud_audio_set_itf_close_EP_cb(u8 rhport, const tusb_control_request_t* p_request)
|
||||||
|
{
|
||||||
|
stopMicrophoneCapture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
3
examples/usb-microphone/arm7/source/microphone.h
Normal file
3
examples/usb-microphone/arm7/source/microphone.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void mic_initialize();
|
||||||
97
examples/usb-microphone/arm7/source/tusb_config.h
Normal file
97
examples/usb-microphone/arm7/source/tusb_config.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Board Specific Configuration
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||||
|
#ifndef BOARD_TUD_RHPORT
|
||||||
|
#define BOARD_TUD_RHPORT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort max operational speed can defined by board.mk
|
||||||
|
#ifndef BOARD_TUD_MAX_SPEED
|
||||||
|
#define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// COMMON CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// defined by compiler flags for flexibility
|
||||||
|
#ifndef CFG_TUSB_MCU
|
||||||
|
#define CFG_TUSB_MCU OPT_MCU_DSPICO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TUP_DCD_ENDPOINT_MAX 16
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_OS
|
||||||
|
#define CFG_TUSB_OS OPT_OS_CUSTOM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_DEBUG
|
||||||
|
#define CFG_TUSB_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Enable Device stack
|
||||||
|
#define CFG_TUD_ENABLED 1
|
||||||
|
|
||||||
|
// Default is max speed that hardware controller could support with on-chip PHY
|
||||||
|
#define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
|
||||||
|
|
||||||
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
|
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||||
|
* into those specific section.
|
||||||
|
* e.g
|
||||||
|
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||||
|
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||||
|
*/
|
||||||
|
#ifndef CFG_TUSB_MEM_SECTION
|
||||||
|
#define CFG_TUSB_MEM_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_MEM_ALIGN
|
||||||
|
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// DEVICE CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------- CLASS -------------//
|
||||||
|
#define CFG_TUD_CDC 0
|
||||||
|
#define CFG_TUD_MSC 0
|
||||||
|
#define CFG_TUD_HID 0
|
||||||
|
#define CFG_TUD_MIDI 0
|
||||||
|
#define CFG_TUD_AUDIO 1
|
||||||
|
#define CFG_TUD_VENDOR 0
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// AUDIO CLASS DRIVER CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE 32728
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
|
||||||
|
|
||||||
|
#define CFG_TUD_AUDIO_ENABLE_EP_IN 1
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX 2 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX 1 // Driver gets this info from the descriptors - we define it here to use it to setup the descriptors and to do calculations with it below - be aware: for different number of channels you need another descriptor!
|
||||||
|
#define CFG_TUD_AUDIO_EP_SZ_IN TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX)
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX CFG_TUD_AUDIO_EP_SZ_IN
|
||||||
|
#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ 256 //(TUD_OPT_HIGH_SPEED ? 8 : 1) * CFG_TUD_AUDIO_EP_SZ_IN // Example write FIFO every 1ms, so it should be 8 times larger for HS device
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
94
examples/usb-microphone/arm7/source/usb_descriptors.cpp
Normal file
94
examples/usb-microphone/arm7/source/usb_descriptors.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "UsbStringDescriptor.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
|
||||||
|
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
|
||||||
|
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||||
|
*
|
||||||
|
* Auto ProductID layout's Bitmap:
|
||||||
|
* [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB]
|
||||||
|
*/
|
||||||
|
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
|
||||||
|
#define USB_PID (0x5000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||||
|
_PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
|
||||||
|
|
||||||
|
const u8* tud_descriptor_device_cb(void)
|
||||||
|
{
|
||||||
|
static const tusb_desc_device_t deviceDescriptor =
|
||||||
|
{
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
|
||||||
|
// Use Interface Association Descriptor (IAD) for Audio
|
||||||
|
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
|
||||||
|
.idVendor = 0xCafe,
|
||||||
|
.idProduct = USB_PID,
|
||||||
|
.bcdDevice = 0x0100,
|
||||||
|
|
||||||
|
.iManufacturer = STRID_MANUFACTURER,
|
||||||
|
.iProduct = STRID_PRODUCT,
|
||||||
|
.iSerialNumber = STRID_SERIAL,
|
||||||
|
|
||||||
|
.bNumConfigurations = 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
return (const u8*)&deviceDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_AUDIO_MIC_ONE_CH_DESC_LEN)
|
||||||
|
|
||||||
|
const u8* tud_descriptor_configuration_cb(u8 index)
|
||||||
|
{
|
||||||
|
(void)index;
|
||||||
|
|
||||||
|
static const u8 configurationDescriptor[] =
|
||||||
|
{
|
||||||
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
|
||||||
|
|
||||||
|
TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(0, STRID_AUDIO_INTERFACE,
|
||||||
|
CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * 8,
|
||||||
|
EPNUM_AUDIO_IN, CFG_TUD_AUDIO_EP_SZ_IN)
|
||||||
|
};
|
||||||
|
|
||||||
|
return configurationDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u16* tud_descriptor_string_cb(u8 index, u16 langid)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case STRID_LANGID:
|
||||||
|
{
|
||||||
|
static const UsbStringDescriptor<2> descriptor(0x0409);
|
||||||
|
return (const u16*)&descriptor;
|
||||||
|
}
|
||||||
|
case STRID_MANUFACTURER:
|
||||||
|
{
|
||||||
|
return USB_STRING_DESCRIPTOR(u"LNH");
|
||||||
|
}
|
||||||
|
case STRID_PRODUCT:
|
||||||
|
{
|
||||||
|
return USB_STRING_DESCRIPTOR(u"DSpico Microphone Example");
|
||||||
|
}
|
||||||
|
case STRID_SERIAL:
|
||||||
|
{
|
||||||
|
return USB_STRING_DESCRIPTOR(u"123456789");
|
||||||
|
}
|
||||||
|
case STRID_AUDIO_INTERFACE:
|
||||||
|
{
|
||||||
|
return USB_STRING_DESCRIPTOR(u"DSpico Microphone");
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
examples/usb-microphone/arm7/source/usb_descriptors.h
Normal file
24
examples/usb-microphone/arm7/source/usb_descriptors.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
STRID_LANGID = 0,
|
||||||
|
STRID_MANUFACTURER,
|
||||||
|
STRID_PRODUCT,
|
||||||
|
STRID_SERIAL,
|
||||||
|
STRID_AUDIO_INTERFACE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
ITF_NUM_AUDIO_CONTROL = 0,
|
||||||
|
ITF_NUM_AUDIO_STREAMING,
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define UAC2_ENTITY_MIC_INPUT_TERMINAL 0x01
|
||||||
|
#define UAC2_ENTITY_FEATURE_UNIT 0x02
|
||||||
|
#define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x03
|
||||||
|
#define UAC2_ENTITY_CLOCK 0x04
|
||||||
|
|
||||||
|
#define EPNUM_AUDIO_IN 0x81
|
||||||
152
examples/usb-microphone/arm9/Makefile
Normal file
152
examples/usb-microphone/arm9/Makefile
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source \
|
||||||
|
source/core
|
||||||
|
INCLUDES := include source ../common
|
||||||
|
DATA := data
|
||||||
|
GRAPHICS := gfx
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -marm -mthumb-interwork -DLIBTWL_ARM9 -DARM9
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2\
|
||||||
|
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
|
||||||
|
-ffunction-sections -fdata-sections\
|
||||||
|
-ffast-math \
|
||||||
|
-fno-devirtualize-speculatively \
|
||||||
|
-Werror=return-type \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE)
|
||||||
|
CXXFLAGS := $(CFLAGS) -std=gnu++23 -Wno-volatile -fno-rtti -fno-exceptions -fno-threadsafe-statics\
|
||||||
|
-Wsuggest-override -Werror=suggest-override
|
||||||
|
|
||||||
|
CFLAGS += -Werror=implicit-function-declaration
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH) $(INCLUDE) -march=armv5te -mtune=arm946e-s
|
||||||
|
|
||||||
|
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),--gc-sections,--use-blx -ffunction-sections -fdata-sections
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -ltwl9 -lnds9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS) $(CURDIR)/../../../libs/libtwl/libtwl9 $(CURDIR)/../../../libs/libtwl/common
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export ARM9ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(PNGFILES:.png=.o)\
|
||||||
|
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf *.nds* *.bin
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM9ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
%.nft2.o : %.nft2
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# This rule creates assembly source files using grit
|
||||||
|
# grit takes an image file and a .grit describing how the file is to be processed
|
||||||
|
# add additional rules like this for each image extension
|
||||||
|
# you use in the graphics folders
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.s %.h: %.png %.grit
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
grit $< -fts -o$*
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
51
examples/usb-microphone/arm9/source/main.cpp
Normal file
51
examples/usb-microphone/arm9/source/main.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include <nds/ndstypes.h>
|
||||||
|
#include <libtwl/gfx/gfxStatus.h>
|
||||||
|
#include <libtwl/mem/memExtern.h>
|
||||||
|
#include <libtwl/rtos/rtosIrq.h>
|
||||||
|
#include <libtwl/rtos/rtosThread.h>
|
||||||
|
#include <libtwl/rtos/rtosEvent.h>
|
||||||
|
#include <libtwl/ipc/ipcSync.h>
|
||||||
|
#include <libtwl/ipc/ipcFifoSystem.h>
|
||||||
|
|
||||||
|
static rtos_event_t sVblankEvent;
|
||||||
|
|
||||||
|
static void vblankIrq(u32 irqMask)
|
||||||
|
{
|
||||||
|
rtos_signalEvent(&sVblankEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
*(vu32*)0x04000000 = 0x10000;
|
||||||
|
*(vu16*)0x05000000 = 31 << 5;
|
||||||
|
*(vu16*)0x0400006C = 0;
|
||||||
|
|
||||||
|
mem_setDsCartridgeCpu(EXMEMCNT_SLOT1_CPU_ARM7);
|
||||||
|
|
||||||
|
rtos_initIrq();
|
||||||
|
rtos_startMainThread();
|
||||||
|
ipc_initFifoSystem();
|
||||||
|
|
||||||
|
rtos_createEvent(&sVblankEvent);
|
||||||
|
|
||||||
|
while (ipc_getArm7SyncBits() != 7);
|
||||||
|
|
||||||
|
ipc_setArm9SyncBits(6);
|
||||||
|
|
||||||
|
rtos_setIrqFunc(RTOS_IRQ_VBLANK, vblankIrq);
|
||||||
|
rtos_enableIrqMask(RTOS_IRQ_VBLANK);
|
||||||
|
gfx_setVBlankIrqEnabled(true);
|
||||||
|
|
||||||
|
*(vu16*)0x05000000 = 0;
|
||||||
|
|
||||||
|
*(vu32*)0x04001000 = 0x10000;
|
||||||
|
*(vu16*)0x05000400 = 0;
|
||||||
|
*(vu16*)0x0400106C = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
rtos_waitEvent(&sVblankEvent, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BIN
examples/usb-microphone/icon.bmp
Normal file
BIN
examples/usb-microphone/icon.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 630 B |
Submodule libs/libtwl updated: 60a213bd42...5988d357ac
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user