Skip to content

Commit d91869a

Browse files
authored
Merge pull request hathach#2105 from kholia/cdc_uac2_example
Add CDC+UAC2 composite device example for Pico
2 parents e5b1718 + d89fc07 commit d91869a

File tree

11 files changed

+1162
-0
lines changed

11 files changed

+1162
-0
lines changed

examples/device/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ family_add_subdirectory(board_test)
1313
family_add_subdirectory(cdc_dual_ports)
1414
family_add_subdirectory(cdc_msc)
1515
family_add_subdirectory(cdc_msc_freertos)
16+
family_add_subdirectory(cdc_uac2)
1617
family_add_subdirectory(dfu)
1718
family_add_subdirectory(dfu_runtime)
1819
family_add_subdirectory(dynamic_configuration)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
cmake_minimum_required(VERSION 3.17)
2+
3+
include(${CMAKE_CURRENT_SOURCE_DIR}/../../../hw/bsp/family_support.cmake)
4+
5+
# gets PROJECT name for the example (e.g. <BOARD>-<DIR_NAME>)
6+
family_get_project_name(PROJECT ${CMAKE_CURRENT_LIST_DIR})
7+
8+
project(${PROJECT} C CXX ASM)
9+
10+
# Checks this example is valid for the family and initializes the project
11+
family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
12+
13+
# Espressif has its own cmake build system
14+
if(FAMILY STREQUAL "espressif")
15+
return()
16+
endif()
17+
18+
add_executable(${PROJECT})
19+
20+
# Example source
21+
target_sources(${PROJECT} PUBLIC
22+
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_app.c
23+
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
24+
${CMAKE_CURRENT_SOURCE_DIR}/src/uac2_app.c
25+
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
26+
)
27+
28+
# Example include
29+
target_include_directories(${PROJECT} PUBLIC
30+
${CMAKE_CURRENT_SOURCE_DIR}/src
31+
)
32+
33+
# Configure compilation flags and libraries for the example... see the corresponding function
34+
# in hw/bsp/FAMILY/family.cmake for details.
35+
family_configure_device_example(${PROJECT} noos)
36+
37+
# Uncomment me to enable UART based debugging
38+
# pico_enable_stdio_uart(${PROJECT} 1)

examples/device/cdc_uac2/Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include ../../make.mk
2+
3+
INC += \
4+
src \
5+
$(TOP)/hw \
6+
7+
# Example source
8+
EXAMPLE_SOURCE += \
9+
src/cdc_app.c \
10+
src/main.c \
11+
src/uac2_app.c \
12+
src/usb_descriptors.c \
13+
14+
SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
15+
16+
include ../../rules.mk

examples/device/cdc_uac2/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#### Composite CDC + UAC2 on Pico
2+
3+
This example provides a composite CDC + UAC2 device on top of a Raspberry Pi
4+
Pico board.
5+
6+
7+
#### Use Cases
8+
9+
- The CDC + UAC2 composite device happens to be important, especially in the
10+
amateur radio community.
11+
12+
Modern radios (`rigs`) like Icom IC-7300 + IC-705 expose a sound card and a
13+
serial device (`composite device`) to the computer over a single USB cable.
14+
This allows for Audio I/O and CAT control over a single USB cable which is
15+
very convenient.
16+
17+
By including and maintaining this example in TinyUSB repository, we enable
18+
the amateur radio community to build (`homebrew`) radios with similar
19+
functionality as the (expensive) commercial rigs.
20+
21+
This PR is important in bridging this specific gap between the commercial
22+
rigs and homebrew equipment.
23+
24+
- https://digirig.net/digirig-mobile-rev-1-9/ is a digital interface for
25+
interfacing radios (that lack an inbuilt digital interface) with computers.
26+
Digirig Mobile works brilliantly (is OSS!) and is a big improvement over
27+
traditional digital interfaces (like the SignaLink USB Interface). By using a
28+
Raspberry Pi Pico powered CDC + UAC2 composite device, we can simplify the
29+
Digirig Mobile schematic, drastically reduce the manufacturing cost, and
30+
(again) enable the homebrewers community to homebrew a modern digital interface
31+
with ease themselves.
32+
33+
34+
#### Build Steps
35+
36+
```
37+
cd examples/device/cdc_uac2
38+
39+
export PICO_SDK_PATH=$HOME/pico-sdk
40+
41+
cmake -DFAMILY=rp2040 pico .
42+
43+
cmake -DFAMILY=rp2040 -DCMAKE_BUILD_TYPE=Debug # use this for debugging
44+
45+
make BOARD=raspberry_pi_pico all
46+
```
47+
48+
49+
#### Development Notes
50+
51+
Please try to keep this code synchronized with the `uac2_headset` example
52+
included in this repository.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2019 Ha Thach (tinyusb.org)
5+
* Copyright (c) 2022 Angel Molina ([email protected])
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
*/
26+
27+
#include "bsp/board.h"
28+
#include "tusb.h"
29+
#include "common.h"
30+
31+
// Invoked when cdc when line state changed e.g connected/disconnected
32+
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
33+
{
34+
(void) itf;
35+
(void) rts;
36+
37+
if (dtr)
38+
{
39+
// Terminal connected
40+
}
41+
else
42+
{
43+
// Terminal disconnected
44+
}
45+
}
46+
47+
// Invoked when CDC interface received data from host
48+
void tud_cdc_rx_cb(uint8_t itf)
49+
{
50+
uint8_t buf[64];
51+
uint32_t count;
52+
53+
// connected() check for DTR bit
54+
// Most but not all terminal client set this when making connection
55+
if (tud_cdc_connected())
56+
{
57+
if (tud_cdc_available()) // data is available
58+
{
59+
count = tud_cdc_n_read(itf, buf, sizeof(buf));
60+
(void) count;
61+
62+
tud_cdc_n_write(itf, buf, count);
63+
tud_cdc_n_write_flush(itf);
64+
// dummy code to check that cdc serial is responding
65+
board_led_write(0);
66+
board_delay(50);
67+
board_led_write(1);
68+
board_delay(50);
69+
board_led_write(0);
70+
}
71+
}
72+
}

examples/device/cdc_uac2/src/common.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef __COMMON_H__
2+
#define __COMMON_H__
3+
4+
/* Blink pattern
5+
* - 25 ms : streaming data
6+
* - 250 ms : device not mounted
7+
* - 1000 ms : device mounted
8+
* - 2500 ms : device is suspended
9+
*/
10+
enum
11+
{
12+
BLINK_STREAMING = 25,
13+
BLINK_NOT_MOUNTED = 250,
14+
BLINK_MOUNTED = 1000,
15+
BLINK_SUSPENDED = 2500,
16+
};
17+
18+
enum
19+
{
20+
VOLUME_CTRL_0_DB = 0,
21+
VOLUME_CTRL_10_DB = 2560,
22+
VOLUME_CTRL_20_DB = 5120,
23+
VOLUME_CTRL_30_DB = 7680,
24+
VOLUME_CTRL_40_DB = 10240,
25+
VOLUME_CTRL_50_DB = 12800,
26+
VOLUME_CTRL_60_DB = 15360,
27+
VOLUME_CTRL_70_DB = 17920,
28+
VOLUME_CTRL_80_DB = 20480,
29+
VOLUME_CTRL_90_DB = 23040,
30+
VOLUME_CTRL_100_DB = 25600,
31+
VOLUME_CTRL_SILENCE = 0x8000,
32+
};
33+
34+
#endif

examples/device/cdc_uac2/src/main.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2020 Jerzy Kasenberg
5+
* Copyright (c) 2022 Angel Molina <[email protected]>
6+
* Copyright (c) 2023 Dhiru Kholia <[email protected]>
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*
26+
*/
27+
28+
#include <stdio.h>
29+
#include <string.h>
30+
31+
#include "bsp/board.h"
32+
#include "tusb.h"
33+
#include "common.h"
34+
35+
extern uint32_t blink_interval_ms;
36+
37+
#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
38+
#include "pico/stdlib.h"
39+
#endif
40+
41+
void led_blinking_task(void);
42+
43+
/*------------- MAIN -------------*/
44+
int main(void)
45+
{
46+
board_init();
47+
48+
// init device stack on configured roothub port
49+
tud_init(BOARD_TUD_RHPORT);
50+
51+
#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
52+
stdio_init_all();
53+
#endif
54+
55+
TU_LOG1("CDC UAC2 example running\r\n");
56+
57+
while (1)
58+
{
59+
tud_task(); // TinyUSB device task
60+
led_blinking_task();
61+
62+
#if (CFG_TUSB_MCU == OPT_MCU_RP2040)
63+
// printf("Hello, world!\n");
64+
#endif
65+
}
66+
67+
return 0;
68+
}
69+
70+
//--------------------------------------------------------------------+
71+
// Device callbacks
72+
//--------------------------------------------------------------------+
73+
74+
// Invoked when device is mounted
75+
void tud_mount_cb(void)
76+
{
77+
blink_interval_ms = BLINK_MOUNTED;
78+
}
79+
80+
// Invoked when device is unmounted
81+
void tud_umount_cb(void)
82+
{
83+
blink_interval_ms = BLINK_NOT_MOUNTED;
84+
}
85+
86+
// Invoked when usb bus is suspended
87+
// remote_wakeup_en : if host allow us to perform remote wakeup
88+
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
89+
void tud_suspend_cb(bool remote_wakeup_en)
90+
{
91+
(void)remote_wakeup_en;
92+
blink_interval_ms = BLINK_SUSPENDED;
93+
}
94+
95+
// Invoked when usb bus is resumed
96+
void tud_resume_cb(void)
97+
{
98+
blink_interval_ms = BLINK_MOUNTED;
99+
}

0 commit comments

Comments
 (0)