Author Topic: RP2040: how to use FreeRTOS with TinyUSB?  (Read 2793 times)

0 Members and 1 Guest are viewing this topic.

Offline mblinovTopic starter

  • Contributor
  • Posts: 43
  • Country: gb
RP2040: how to use FreeRTOS with TinyUSB?
« on: March 12, 2023, 12:01:00 pm »
Hi all,

Quite basic question but the answer eludes me. How to sanely use FreeRTOS with the TinyUSB that is shipped with pico-sdk?

So pico-sdk contains TinyUSB as part of its distribution. If you clone pico-sdk, you will find it under pico-sdk\lib\tinyusb.

However, here's the catch: If we look in pico-sdk\lib\tinyusb\hw\bsp\rp2040\family.cmake (note it is a git submodule), which is the file that specifies compilation options for the RP2040 MCU, we find that CFG_TUSB_OS is hardcoded to OPT_OS_PICO:

Code: [Select]
        target_compile_definitions(tinyusb_common_base INTERFACE
                        CFG_TUSB_MCU=OPT_MCU_RP2040
                        CFG_TUSB_OS=OPT_OS_PICO
                        #CFG_TUSB_DEBUG=${TINYUSB_DEBUG_LEVEL}
        )

Which is fine for all normal purposes. However, I'd like to use FreeRTOS in my app, and consequently (atleast, it would seem to me) that I need to set this to be OPT_OS_FREERTOS in place of OPT_OS_PICO. Unfortunately, it does not seem to be a configurable option (for the time being I can ofcourse change it directly in the sdk source code.)

Now what I *could* do instead is supply my own tusb_config.h file, and override CFG_TUSB_OS in there instead. I can confirm that the compiler picks up my header file, because I see lots of warnings like

Code: [Select]
warning: "CFG_TUSB_OS" redefined
   46 | #define CFG_TUSB_OS OPT_OS_FREERTOS
      |

Which is "good" since it implies it's picking up my option (but also not good because it's clearly not the right way to go about it!)

However the build fails, I think because it picks it up my header file "too late" so to speak. I get unknown type name and implicit declaration of function errors, which suggests that some object files are being compiled with OPT_OS_PICO while others with OPT_OS_FREERTOS, and consequently some C files are trying to use symbols which haven't been compiled.

I want to know, what is the "correct" way of doing what I'm trying to do? Obviously its trivial to modify the SDK directly, but I really don't want to drag a slightly-custom pico-sdk together with my project.

I seem to have some kind of faint memory of seeing FreeRTOS <-> "Pico OS" interop, atleast as far as the various synchronization primitives go, which would mean that what I'm trying to do is completely needless. But I can't remember where I got this impression from.
« Last Edit: March 12, 2023, 12:06:28 pm by mblinov »
 

Offline mblinovTopic starter

  • Contributor
  • Posts: 43
  • Country: gb
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #1 on: March 12, 2023, 12:42:41 pm »
Ok, so actually its not quite as simple as just changing the pico-sdk\lib\tinyusb\hw\bsp\rp2040\family.cmake file. I still get the same unknown type name and implicit declaration of function errors, but they are *not* due to some hand-wavy inclusion error.

I neglected to post these errors in the OP, here they are below:

Code: [Select]
[4/5] Building C object [...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c.obj
FAILED: [...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c.obj

[...trimmed content...]

[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c:38:8: error: unknown type name 'critical_section_t'
   38 | static critical_section_t one_shot_timer_crit_sec;
      |        ^~~~~~~~~~~~~~~~~~
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c: In function 'timer_task':
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c:49:9: warning: implicit declaration of function 'critical_section_is_initialized' [-Wimplicit-function-declaration]
   49 |     if (critical_section_is_initialized(&one_shot_timer_crit_sec)) {
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c:50:9: warning: implicit declaration of function 'critical_section_enter_blocking' [-Wimplicit-function-declaration]
   50 |         critical_section_enter_blocking(&one_shot_timer_crit_sec);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c:52:9: warning: implicit declaration of function 'critical_section_exit' [-Wimplicit-function-declaration]
   52 |         critical_section_exit(&one_shot_timer_crit_sec);
      |         ^~~~~~~~~~~~~~~~~~~~~
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c: In function 'stdio_usb_init':
[...long path...]/pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c:213:9: warning: implicit declaration of function 'critical_section_init_with_lock_num' [-Wimplicit-function-declaration]
  213 |         critical_section_init_with_lock_num(&one_shot_timer_crit_sec, next_striped_spin_lock_num());
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ninja: build stopped: subcommand failed.

Now, if I undo all my changes (that is, let CFG_TUSB_OS=OPT_OS_PICO) and look at who includes who, the following comes up:

If we select CFG_TUSB_OS=OPT_OS_PICO (the default), then the following inclusion chain occurs:

Code: [Select]
pico-sdk\src\rp2_common\pico_stdio_usb\stdio_usb.c:
- pico-sdk\lib\tinyusb\src\tusb.h
  - pico-sdk\lib\tinyusb\src\osal\osal.h
    (here it is decided who to include based on OS)
    - pico-sdk\lib\tinyusb\src\osal\osal_pico.h
      - pico-sdk\src\common\pico_sync\include\pico\critical_section.h
        (Here, `struct critical_section` is defined (among others.))
  - pico-sdk\src\rp2_common\pico_stdio_usb\include\pico\stdio_usb.h

However, if we select CFG_TUSB_OS=OPT_OS_FREERTOS, then the following inclusion chain occurs:

Code: [Select]
pico-sdk\src\rp2_common\pico_stdio_usb\stdio_usb.c:
- pico-sdk\lib\tinyusb\src\tusb.h
  - pico-sdk\lib\tinyusb\src\osal\osal.h
    (here it is decided who to include based on OS)
    - pico-sdk\lib\tinyusb\src\osal\osal_freertos.h
  - pico-sdk\src\rp2_common\pico_stdio_usb\include\pico\stdio_usb.h

We never did include critical_section.h, and as a consequence the build fails, since the stdio_usb.c file is implemented using those primitives.

I'm inclined to suggest that this is an oversight: The printing logic (stdio_usb.c) is a *consumer* of the TinyUSB library, not an integral part of it. By that logic, it should not depend *at all* on whether TinyUSB itself is targetting FreeRTOS, or using pico-sdk primitives, or whatever.

Infact the fix is trivial: We simply need to include critical_section.h directly from stdio_usb.c:

Code: [Select]
diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb.c b/src/rp2_common/pico_stdio_usb/stdio_usb.c
index 32f1f33..c91af99 100644
--- a/src/rp2_common/pico_stdio_usb/stdio_usb.c
+++ b/src/rp2_common/pico_stdio_usb/stdio_usb.c
@@ -16,6 +16,7 @@
 #include "pico/time.h"
 #include "pico/stdio/driver.h"
 #include "pico/mutex.h"
+#include "pico/critical_section.h"
 #include "hardware/irq.h"
 #include "device/usbd_pvt.h" // for usbd_defer_func
 

Offline dobsonr741

  • Frequent Contributor
  • **
  • Posts: 672
  • Country: us
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #2 on: March 12, 2023, 03:16:17 pm »
Perhaps worthy of a pull request?
 

Offline mblinovTopic starter

  • Contributor
  • Posts: 43
  • Country: gb
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #3 on: March 12, 2023, 06:08:27 pm »
Perhaps worthy of a pull request?

To be honest I'm still not sure if what I'm trying to do isn't completely insane.

I just came across the following text in the RP2040 SDK manual:



In any case: Continuing from my previous post... Unfortunately I don't remember the details anymore, I think what bit me was that if you want to call tud_task and board_init, you need to add to your CMake project the TinyUSB link targets, e.g.:

Code: [Select]
target_link_libraries(${CMAKE_PROJECT_NAME} pico_stdlib tinyusb_device tinyusb_board FreeRTOS-Kernel FreeRTOS-Kernel-Heap3 pico_unique_id)

And as explained in the manual above, linking against tinyusb_device and tinyusb_board actually has a consequence on codegen: There is code in the pico-sdk library that detects you're explicitly linking against TinyUSB, and will turn off the stdio-USB printing logic (or some of it.)

Basically there is really quite intricate interplay between printf, TinyUSB, and the larger pico-sdk library. Consequently if you want to do anything that isn't absolutely out-the-box standard printf-over-USB, it seems best to create a completely custom TinyUSB endpoint from scratch, and use that.

You're not completely left out in the cold though, as the stdio subsystem provides a function called stdio_set_driver_enabled, which lets you provide a stdio_driver_t structure.

I then copied the files pico-sdk\src\rp2_common\pico_stdio_usb\stdio_usb.c and pico-sdk\src\rp2_common\pico_stdio_usb\stdio_usb_descriptors.c, modified slightly to work standalone, and had essentially a CDC endpoint that behaved exactly like printf, only I can now set the manufacturer string, manage it from FreeRTOS, etc.

« Last Edit: March 12, 2023, 06:15:23 pm by mblinov »
 

Offline rapzak

  • Newbie
  • Posts: 3
  • Country: dk
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #4 on: March 24, 2023, 07:47:46 pm »
Hi,

Have you found any better/easy solution to this problem?

I am now in same boart...

/Kasper
 

Offline mblinovTopic starter

  • Contributor
  • Posts: 43
  • Country: gb
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #5 on: March 25, 2023, 04:41:15 pm »
Unfortunately not. I did open a discussion in the TinyUSB github repo, so there is some upstream visibility into this problem.
 

Offline rapzak

  • Newbie
  • Posts: 3
  • Country: dk
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #6 on: March 26, 2023, 09:37:36 pm »
Hi,

Thanks for the update.

I think the Pico SDK could have and option for this input in the cmake file like these:

# create map/bin/hex file etc.
pico_add_extra_outputs(${NAME})

# enable usb output, disable uart output
pico_enable_stdio_usb(${NAME} 0)
pico_enable_stdio_uart(${NAME} 0)

/Kasper


Unfortunately not. I did open a discussion in the TinyUSB github repo, so there is some upstream visibility into this problem.

 

Offline rapzak

  • Newbie
  • Posts: 3
  • Country: dk
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #8 on: March 27, 2023, 05:30:26 am »
I would have thought that "tinyUSB" was a sort of "full stack" USB implementation designed for systems that don't use an RTOS, so that if you want to use FreeRTOS on an RP2040, you'd have to find a FreeRTOS USB stack.  Probably that would rely on lower-level USB hardware drivers, and use the FreeRTOS scheduling primitives for the more complicated levels, instead of whatever mechanisms TinyUB uses to implement multiple IO streams in a taskless environment.     (perhaps not.  It seems that FreeRTOS is lower level and doesn't have a standardized USB abstraction.)

 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: RP2040: how to use FreeRTOS with TinyUSB?
« Reply #9 on: March 27, 2023, 06:31:15 pm »
I would have thought that "tinyUSB" was a sort of "full stack" USB implementation designed for systems that don't use an RTOS, so that if you want to use FreeRTOS on an RP2040, you'd have to find a FreeRTOS USB stack.  Probably that would rely on lower-level USB hardware drivers, and use the FreeRTOS scheduling primitives for the more complicated levels, instead of whatever mechanisms TinyUB uses to implement multiple IO streams in a taskless environment.     (perhaps not.  It seems that FreeRTOS is lower level and doesn't have a standardized USB abstraction.)

TinyUSB supports no OS, FreeRTOS, RT-Thread and Mynewt. The best bet is not to think, but to look at the project. ;D https://github.com/hathach/tinyusb
The problem here is that TinyUSB's FreeRTOS support for the RP2040 is not quite there yet. It's not a limitation of TinyUSB, just something that is not fully ready yet.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf