The USBMassStorage library calls USBMS.SDIOInit() to take control of the SD card. If your video pipeline already initialized the SD card (e.g., for MP4 recording), the USB driver tries to reinitialize it, causing conflicts
Hi @DevomechSolutions ,
Would it be possible for you to init SDIO first before doing MP4 recording? I have tested this flow which did not cause initialization conflict.
Thank you.
Hey @KevinKL
Would it be possible to give us some more explanation on this? i didnt quite get it? may be if possible you can share you code snippet with me.
Hi @DevomechSolutions ,
Please refer to the example code snippet below. The MP4 recording is started after after calling USBMS.SDIOInit().
#include "USBMassStorage.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "MP4Recording.h"
#define CHANNEL 0
// Default preset configurations for each video channel:
// Channel 0 : 1920 x 1080 30FPS H264
// Channel 1 : 1280 x 720 30FPS H264
VideoSetting config(CHANNEL);
MP4Recording mp4;
StreamIO videoStreamer(1, 1); // 1 Input Video -> 1 Output RTSP
USBMassStorage USBMS;
#define PRINT_USB_OTG_CONNECTION_STATUS 1
int connection_status = 0;
void setup()
{
Serial.begin(115200);
USBMS.USBInit();
USBMS.SDIOInit();
USBMS.USBStatus();
USBMS.initializeDisk();
USBMS.loadUSBMassStorageDriver();
// Configure camera video channel with video format information
Camera.configVideoChannel(CHANNEL, config);
Camera.videoInit();
// Configure MP4 with identical video format information
// Configure MP4 recording settings
mp4.configVideo(config);
mp4.setRecordingDuration(5);
mp4.setRecordingFileCount(1);
mp4.setRecordingFileName("TestRecordingVideoOnly");
mp4.setRecordingDataType(STORAGE_VIDEO); // Set MP4 to record video only
// Configure StreamIO object to stream data from video channel to MP4 recording
videoStreamer.registerInput(Camera.getStream(CHANNEL));
videoStreamer.registerOutput(mp4);
if (videoStreamer.begin() != 0) {
Serial.println("StreamIO link start failed");
}
// Start data stream from video channel
Camera.channelBegin(CHANNEL);
// Start recording MP4 data to SD card
mp4.begin();
delay(1000);
printInfo();
}
void loop()
{
delay(1000);
if (PRINT_USB_OTG_CONNECTION_STATUS) {
connection_status = USBMS.isConnected();
Serial.print("USB OTG connection status: ");
Serial.println(connection_status);
}
}
void printInfo(void)
{
Serial.println(" ");
Serial.println("------------------------------");
Serial.println("- Summary of Streaming -");
Serial.println("------------------------------");
Camera.printInfo();
Serial.println("- MP4 Recording Information -");
mp4.printInfo();
}
Thank you.
Thanks! it worked for a single channel video,
for 2 channels enabled its causing problem
Attached are the logs appear when two channels are enabled alogn with the OTG.
== Rtl8735b IoT Platform ==
[Normal mode]
BootFromNORFlash
[Start Boot ROM...]
=== Load PARTBL ===
=== Load Done ===
=== Load ISP_IQ ===
[fcs chk pass]
ISP_IQ @ 0x8461080, 0x2ff80, 0x0
mfcs_data version 0x00010001
fcs_data version 0x00010101
=== Process ISP_IQ ===
=== Load Done ===
=== Load BL ===
[Image Start Table @ 0x18200]
=== Load Done ===
== Boot Loader ==
Sep 5 2025:11:53:02
=== Load FCS Para ===
=== Load Done ===
[crc pass]
=== Load ISP_IQ Sensor ===
ISP_IQ @ 0x8461080, 0x2ff80
=== Process ISP_IQ ===
=== Load Done ===
=== Load FW1 ===
FW_ISP_IQ @ 0x8061080, 0x31f80
=== Process FW_ISP_IQ ===
DRAM_TYPE is DDR2 128MB.
ddr_freq = 533
VOE flash @ 0x8093080, 0x81f80
FCS KM_status 0x00002081 err 0x0000200a
Wait KM fcs done 0 us
FCS TM_status 0x003f0000
store fcs data for application
It don't do the sensor initial process
RAM TM_STATUS 0x00bf1208 err 0x00001208
read fcs_status 0x000000bf
read fcs_status 0x000000bf
=== Process VOE IMG ===
[Image Start Table @ 0x20106200]
RAM Load @ 0x8115100->0x20106200, 0x5f64
DDR Load @ 0x811c080->0x70100000, 0xcefad
=== FW Load Done ===
Boot Loader <==
== RAM Start ==
Build @ 18:41:56, Sep 23 2025
set ASP print off
$8735b>set ASP print off
OTG DRIVER VER: 0826
[INFO] USB init status 0
SD_Init 0
sector number: 62333952
capacity: 30436 MB
[INFO] USB MSC driver load done, Available heap [0x59b8e00]
*******************************USB OTG connection status: 1
****DS3231 detected on I2C bus*****
year_Day 311
Current local time and date: Sat Nov 8 14:06:07 2025
The sd gpio pin has already init
Register disk driver to Fatfs.
FATFS Register: disk driver 0
The card is inited 0
part_count = 0
write something to "log_2025_11_8.csv"
[video_voe_presetting] fps:30 w:1920 h:1080
fwin(1),enc_en(0),IQ_OFFSET = 0x17b60
fwin(1),enc_en(0),SENSOR_OFFSET = 0x2fba0
sensor id 1 iq_data 17b60 sensor_data 2fba0
VOE not init
VOE_OUT_CMD type 2 command fail -1
fwin(1),enc_en(0),IQ_OFFSET = 0x17b60
fwin(1),enc_en(0),SENSOR_OFFSET = 0x2fba0
sensor id 1 iq_data 17b60 sensor_data 2fba0
ctx->enc_info.frameLength * 2 = 2048
hal_voe_ready 0x0 0xbf1208
read fcs_status 0x000000bf
[video_init] uvcd iq is null, use default.
[video_init] uvcd SNR is null, use default.
IQ:FW size (98342)
sensor:date 2024/9/12 version:RTL8735B_VOE_1.5.7.0
sensor:FW size (5412)
sensor timestamp: 2024/09/12
iq timestamp: 2023/05/15 14:48:54
voe_heap malloc 0x702e6620, size 37096192
ISP:1 ENC:1 H265:1 NN:1
hal_voe_ready 0x0 0xbf1208
voe :RTL8735B_VOE_1.6.5.0
sensor:RTL8735B_VOE_1.5.7.0
hal :RTL8735B_VOE_1.6.5.0
load time sensor:119us iq:1247us itcm:0us dtcm:0us ddr:0us ddr2:0us
[video_pre_init_procedure] START
hal_voe_send2voe too long 50076 cmd 0x00000206 p1 0x00000000 p2 0x00000000
Set H264 default HIGH profile
rc_version RC_v1
***************Camera init successfull***************
INIT COMPLETE
button pressed
button pressed
Start MP4 recording (1 files)
STORAGE_INIT
mp4_init_buffer error: allocate mp4_ctx->moov_box fail
mp4_init_buffer error
button pressed
#include "camera_ops.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "MP4Recording.h"
#include "AudioStream.h"
#include "AudioEncoder.h"
#include "AmebaFatFS.h"
#include "rtc_ops.h"
#include "speaker_ops.h"
extern AmebaFatFS fs;
extern dateTime_t dt;
char filename[40] = "";
char image_filename[40] = "";
bool isCamera_init = false;
#define CHANNELV 1
#define CHANNELS 0
// VideoSetting configV(CHANNELV);
VideoSetting configV(VIDEO_HD, CAM_FPS, VIDEO_H264_JPEG, 1);
// VideoSetting configS(VIDEO_FHD, CAM_FPS, VIDEO_JPEG, 1);
AudioSetting configA(0);
Audio audio;
AAC aac;
MP4Recording mp4;
StreamIO audioStreamer(1, 1); // 1 Input Audio -> 1 Output AAC
StreamIO avMixStreamer(2, 1); // 2 Input Video + Audio -> 1 Output MP4
Error_Camera_e cam_err;
Error_Camera_e ameba_camera_init(void)
{
Camera.configVideoChannel(CHANNELV, configV);
// Camera.configVideoChannel(CHANNELS, configS);
Camera.videoInit();
// Configure audio peripheral for audio data output
audio.configAudio(configA);
audio.begin();
// Configure AAC audio encoder
aac.configAudio(configA);
aac.begin();
// Configure MP4 with identical video format information
// Configure MP4 recording settings
mp4.configVideo(configV);
mp4.configAudio(configA, CODEC_AAC);
mp4.setRecordingDuration(36000);
mp4.setRecordingFileCount(1);
// mp4.setRecordingDataType(STORAGE_VIDEO);
// Configure StreamIO object to stream data from audio channel to AAC encoder
audioStreamer.registerInput(audio);
audioStreamer.registerOutput(aac);
if (audioStreamer.begin() != 0)
{
// Serial.println("StreamIO link start failed");
return ERR_AUIDO_STREAMER;
}
// Configure StreamIO object to stream data from video channel and AAC encoder to MP4 recording
avMixStreamer.registerInput1(Camera.getStream(CHANNELV));
avMixStreamer.registerInput2(aac);
avMixStreamer.registerOutput(mp4);
if (avMixStreamer.begin() != 0)
{
// Serial.println("StreamIO link start failed");
return ERR_AV_MIXER;
}
// Camera.channelBegin(CHANNELS);
Camera.channelBegin(CHANNELV);
delay(1000);
int status = Camera.cameraOpenStatus();
if (status == 1)
{
isCamera_init = true;
Serial.println("***************Camera init successfull***************\n");
return ERR_OK;
}
isCamera_init = false;
Serial.println("*****************Failed to init Camera**************\n");
return ERR_CAMERA_INIT;
}
void capture_and_save_image(void)
{
if (false == isCamera_init)
{
return;
}
get_dateTime();
uint32_t img_addr = 0;
uint32_t img_len = 0;
snprintf(image_filename, sizeof(image_filename), "cameraImage_%hu_%hhu_%hhu_%hhu_%hhu_%hhu.jpg", dt.yy, dt.mm, dt.dd, dt.h, dt.m, dt.s);
File file = fs.open(String(fs.getRootPath()) + String(image_filename));
// delay(1000);
Camera.getImage(CHANNELV, &img_addr, &img_len);
file.write((uint8_t *)img_addr, img_len);
file.close();
}
void start_recording(void)
{
if (false == isCamera_init)
{
return;
}
if (!mp4.getRecordingState())
{
snprintf(filename, sizeof(filename), "cameraRecord_%hu_%hhu_%hhu_%hhu_%hhu_%hhu", dt.yy, dt.mm, dt.dd, dt.h, dt.m, dt.s);
mp4.setRecordingFileName(filename);
mp4.begin();
}
}
void stop_recording(void)
{
if(false == isCamera_init)
{
return;
}
if (mp4.getRecordingState())
{
mp4.end();
}
}
when we disconnect the otg from our system we get these logs? although when we disconnect it in your example code we dont get these logs. can you please give us some explanation from where and what can cause these logs? also the otg init some time by itself when we reconnect it at run time but some it doesnt init on itself.
fun_suspend
fun_suspend
fun_suspend
fun_suspend
fun_suspend
fun_suspend
Hi @DevomechSolutions ,
This log is printed from internal source code and it shows the usb function is suspended. This could be due to improper init and deinit flow of USBMS. Please refer to the sample code below for 2 channel camera with USB OTG, I have shifted the initialization of USBMS process to after snapshot and mp4 recording, it works on my end. Please ensure that the delay added after mp4.begin() is longer than your recording duration.
#include "USBMassStorage.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "AudioStream.h"
#include "AudioEncoder.h"
#include "MP4Recording.h"
#include "AmebaFatFS.h"
#define CHANNELV 0
#define CHANNELS 1
#define FILENAME "image_capture.jpg"
VideoSetting configV(0);
VideoSetting configS(VIDEO_FHD, CAM_FPS, VIDEO_JPEG, 1);
AudioSetting configA(0);
Audio audio;
AAC aac;
MP4Recording mp4;
StreamIO audioStreamer(1, 1); // 1 Input Audio -> 1 Output AAC
StreamIO avMixStreamer(2, 1); // 2 Input Video1 + Audio -> 1 Output MP4
USBMassStorage USBMS;
AmebaFatFS fs;
#define PRINT_USB_OTG_CONNECTION_STATUS 1
int connection_status = 0;
uint32_t img_addr = 0;
uint32_t img_len = 0;
void setup()
{
Serial.begin(115200);
// Configure camera video channel with video format information
Camera.configVideoChannel(CHANNELV, configV);
Camera.configVideoChannel(CHANNELS, configS);
Camera.videoInit(CHANNELV);
Camera.videoInit(CHANNELS);
// Configure audio peripheral for audio data output
audio.configAudio(configA);
audio.begin();
// Configure AAC audio encoder
aac.configAudio(configA);
aac.begin();
// Configure MP4 with identical video format information
// Configure MP4 recording settings
mp4.configVideo(configV);
mp4.configAudio(configA, CODEC_AAC);
mp4.setRecordingDuration(5);
mp4.setRecordingFileCount(1);
mp4.setRecordingFileName("TestRecordingVideowithAudio");
// Configure StreamIO object to stream data from audio channel to AAC encoder
audioStreamer.registerInput(audio);
audioStreamer.registerOutput(aac);
if (audioStreamer.begin() != 0) {
Serial.println("StreamIO link start failed");
}
// Configure StreamIO object to stream data from video channels and AAC encoder to MP4 outputs
avMixStreamer.registerInput1(Camera.getStream(CHANNELV));
avMixStreamer.registerInput2(aac);
avMixStreamer.registerOutput1(mp4);
if (avMixStreamer.begin() != 0) {
Serial.println("StreamIO link start failed");
}
// Start data stream from video channel
Camera.channelBegin(CHANNELV);
Camera.channelBegin(CHANNELS);
fs.begin();
File file = fs.open(String(fs.getRootPath()) + String(FILENAME));
delay(1000);
Camera.getImage(CHANNELS, &img_addr, &img_len);
file.write((uint8_t *)img_addr, img_len);
file.close();
// Start recording MP4 data to SD card
mp4.begin();
delay(7000);
printInfo();
fs.end();
USBMS.USBInit();
USBMS.SDIOInit();
USBMS.USBStatus();
USBMS.initializeDisk();
USBMS.loadUSBMassStorageDriver();
}
void loop()
{
delay(1000);
if (PRINT_USB_OTG_CONNECTION_STATUS) {
connection_status = USBMS.isConnected();
Serial.print("USB OTG connection status: ");
Serial.println(connection_status);
}
}
void printInfo(void)
{
Serial.println(" ");
Serial.println("------------------------------");
Serial.println("- Summary of Streaming -");
Serial.println("------------------------------");
Camera.printInfo();
Serial.println("- Audio Information -");
audio.printInfo();
Serial.println("- MP4 Recording Information -");
mp4.printInfo();
}
Thank you.