
Комментарии 22
Очень основательный подход! Следующим этапом было бы: своя печатная плата с расширением памяти и другими фишками под задачи(аппаратное отключение -например...)
Для этого есть утилита H2testw.exe.
это вы под Windows на десктопе проверяете -
что карта в самом деле поддерживает нужную битовую скорость на запись
интересно? Если да, то как вы проверяете скорость записи на СТМ-ке, мне кажется у вас не очень понятно написано, а было бы интересно понять.
Не знаю это только я не понял есть ли у вас проверка при переключении буферов, что очередной буфер для записи свободен, то есть что данные из него полностью ушли на карту?
то как вы проверяете скорость записи на СТМ-ке, мне кажется у вас не очень понятно написано, а было бы интересно понять.
Вот такой модульный тест я написал для проверки скорости записи
Код измерения скорости записи в FAT-FS
/*
tr fat_fs_write
*/
static uint8_t wrData[WRITE_PART_SIZE+1]={0};
bool test_fat_fs_write(void) {
LOG_INFO(TEST, "%s():", __FUNCTION__);
bool res = true;
static uint32_t sn=0;
FRESULT ret;
sn++;
memset(wrData, 0xAA, sizeof(wrData));
FIL File = {0};
uint32_t i = 0;
uint32_t total_size = 0;
uint32_t start_ms = time_get_ms32();
char file_name[80]="";
snprintf(file_name,sizeof(file_name),"TWP%u.bin", sn);
LOG_INFO(TEST,"sizeof:%s ",file_name );
BYTE mode = FA_WRITE | FA_CREATE_NEW |FA_OPEN_ALWAYS;
FRESULT reto = f_open((FIL*)&File, (const TCHAR*) file_name, mode);
LOG_INFO(TEST,"file_name:[%s],ret:%s ",file_name , FatFsResToStr(reto ));
if(FR_EXIST==reto ) {
ret = f_unlink(file_name);
LOG_INFO(TEST,"DeleteFile:[%s],ret:%s ",file_name , FatFsResToStr(ret ));
reto = f_open((FIL*)&File, (const TCHAR*) file_name, mode);
}
while(total_size < WAV_WRITE_SIZE) {
UINT written = 0;
ret = f_write(&File, wrData, WRITE_PART_SIZE, &written);
EXPECT_EQ(FR_OK, ret);
EXPECT_EQ(WRITE_PART_SIZE, written);
if( FR_OK != ret ) {
LOG_ERROR(TEST,"%u,WrError:%s",i, FatFsResToStr(ret ));
break;
}
if(WRITE_PART_SIZE!=written) {
break;
}
total_size += written;
i++;
}
ret = f_close(&File);
LOG_INFO(TEST,"CloseCode:%s " , FatFsResToStr(ret ));
ASSERT_EQ(FR_OK, ret);
uint32_t stop_ms = time_get_ms32();
uint32_t diff_ms = stop_ms - start_ms;
uint32_t data_rate= (1000*total_size) / (diff_ms);
LOG_INFO(TEST,"totalSize:%u Byte,Duration:%u ms,WriteSpeed:%u Byte/s=%f kByte/s",
total_size,
diff_ms,
data_rate,
BYTES_2_KBYTES(data_rate));
float ratio =((float) data_rate / (float) WAV_WRITE_SPEED);
LOG_INFO(TEST,"ratio:%f ",ratio );
ASSERT_GR(WAV_WRITE_SPEED, data_rate);
EXPECT_EQ(WAV_WRITE_SIZE, total_size);
return res;
}так это не тест должен быть, это должна быть встроенная диагностика при переключении буферов в рантайме! Надо обязательно проверять что буфер свободен при переключении, иначе вы и будете ловить артефакты от наложений и не поймете откуда они у вас берутся.
Кстати в этом коде очень странно что вы время на открытие и закрытие файла и всякую другую дребедень тоже охватили:
uint32_t start_ms = time_get_ms32();
char file_name[80]="";
snprintf(file_name,sizeof(file_name),"TWP%u.bin", sn);
LOG_INFO(TEST,"sizeof:%s ",file_name );
BYTE mode = FA_WRITE | FA_CREATE_NEW |FA_OPEN_ALWAYS;
FRESULT reto = f_open((FIL*)&File, (const TCHAR*) file_name, mode);
LOG_INFO(TEST,"file_name:[%s],ret:%s ",file_name , FatFsResToStr(reto ));
// ...
// ...
// ...
ret = f_close(&File);
// ...
// ...
// ...
uint32_t stop_ms = time_get_ms32();Зачем вы все это учитываете как время записи?
Не знаю это только я не понял есть ли у вас проверка при переключении буферов, что очередной буфер для записи свободен, то есть что данные из него полностью ушли на карту?
У меня есть проверка на срыв потока.
Если длительность записи фрагмента превысила таймаут REC_PART_TIMEOUT_US , то происходит аварийная остановка записи.
static inline bool sound_rec_save_part_offset(SoundRecorderHandle_t* Node,
uint32_t offset,
uint32_t need_size) {
bool res = false;
if(Node->cur_save_size < Node->total_file_size) {
UINT written = 0;
uint32_t start_save_us = time_get_us32();
void* buff = (void* ) ( ( (uint32_t ) Node->RxSampleArray) + offset );
FRESULT ret = f_write(&Node->FileToRec, buff, need_size, &written);
uint32_t end_save_us = time_get_us32();
if(FR_OK == ret) {
if(need_size == written) {
Node->cur_save_size += written;
Node->wr_ok_cnt++;
res = true;
} else {
Node->error_size_cnt++;
//LOG_ERROR(SOUND_RECORDER,"WriteSmall:%u Byte", written);
res = sound_recorder_stop_ll(Node);
}
Node->action = SOUND_RECORDER_ACTION_NOPE;
} else {
Node->error_cnt++;
Node->action = SOUND_RECORDER_ACTION_NOPE;
res = sound_recorder_stop_ll(Node);
}
uint32_t diff_us = end_save_us-start_save_us;
if (REC_PART_TIMEOUT_US < diff_us) {
Node->long_write_error_cnt++;
res = sound_recorder_stop_ll(Node);
}
} else {
res = sound_recorder_stop_ll(Node);
}
return res;
}ну вот здесь у вас один f_write
uint32_t start_save_us = time_get_us32();
void* buff = (void* ) ( ( (uint32_t ) Node->RxSampleArray) + offset );
FRESULT ret = f_write(&Node->FileToRec, buff, need_size, &written);
uint32_t end_save_us = time_get_us32();измеряется, и получается он измеряет непонятно что если
FATFS фактическую запись как раз и делает внутри
f_close
Но с точки зрения проверки что буфер свободен это корректно, тем не менее.
Но получается вы используете двойную буферизацию - одна своя, вторая от файловой системы. Это как минимум не очень эффективно, а как максимум будет иметь всякие странные эффекты, которые и приводят к артефактам в записанных данных и которые вы не отладите пока в конце концов не влезете с ногами в код реализации этой файловой системы и ее буферизации. Чужая реализация файловой системы в эмбеддед это почти всегда беда, такая черная дыра в которой размножаются баги безконтрольно. В эмбеддед Операционная Система (ОС) практически не бывает полноценная, там куча ограничений которые еще фиг все найдешь-отловишь. Фактически вы вместо того чтобы заниматься отладкой своего кода вынуждены заниматься исследованием кода этой ОС большую часть времени.
Не, ну на кодеке любой сделает. А вот ежели через ADC и DAC микроконтроллера...
У аудиокодека шире динамический диапазон: 24 бит вместо 12 на MCU. Плюс есть аналоговые предусилитель для микрофона, цифровой фильтр нижних частот.
Звук получается чище и разборчивее.
Все нормально там со звуком у STM32. Используте i2s microphone и sigma delta.
https://habr.com/ru/articles/662141/
Здесь сигма дельта на тaймерах stm32f401
Зачем диктофону частота дискретизации 96 кГц? И тем более 384 кбайт/с, то есть стерео? Ему и 44,1 кГц - много. 32 кГц моно - вполне достаточно. А вот FAT16 - это анахронизм, особенно для диктофона, особенно без сжатия данных. А кодек WM8731 числится устаревшим - его уже не продают на Маузере и Дижикее, по крайней мере поштучно.
Зачем диктофону частота дискретизации 96 кГц? Ему и 44,1 кГц - много. 32 кГц - вполне достаточно.
Я хочу сделать автономный сонар из диктофона.
https://habr.com/ru/articles/868672/
Если повысить частоту дискретизации до 96kHz, то это улучшит разрешение измерения расстояния.
На частоте дискретизации 44100 Hz за один семпл (22.6 us) звук пролетает 331*(1/44100)=7.5mm. Свертка ЛЧМ дает максимум в одном семпле. Получается погрешность измерения расстояния должна быть -/+ 7.5 mm.
На частоте 96k Hz погрешность измерения расстояния должна быть -/+ 3.4 mm.
А кодек WM8731 числится устаревшим - его уже не продают на Маузере и Дижикее.
Зато он прост в программировании (11 регистров всего-лишь) и его можно купить на AliExpress прямо в составе готового модуля

А вот FAT16 - это анахронизм, особенно для диктофона.
Ну а что тут поделаешь, если модульные тесты проходят на FAT16 и проваливаются на FAT32?
А кодек WM8731 числится устаревшим - его уже не продают на Маузере и Дижикее, по крайней мере поштучно.
Какой тогда аудиокодек Вы предлагаете применить?
Все таки стоит на нормальную SD карту делать запись и как было сказано ранее, сделать готовое устройство. Просто на этих макетках как то кустарно получается. А так, сделать печатную плату, красивый корпус, все укомпоновать, добавить кнопки быстрого доступа к командам, небольшой дисплей и будет изделие, а не полуфабрикат.
Автор, я говорил тебе уже, у тебя такой потенциал, а ты каждый раз переизобретаешь велосипед, самокат, колесо и кирпичи. И все бы ничего, дальше макетной платы ты не идёшь, почему?
Статей много, ты делишься информацией, очень круто, а что дальше? Если ты просто хочешь научить всех, показать, как можно делать и что для этого нужно, то хорошо, пусть будет так.
Это проект - интересный, но много НО! Контроллер на макетке, аудиоплата на макетке, какой микрофон - непонятно, как прослушать на диктофоне - непонятно. Управление - непонятно, индикации нет. Схемы устройства нет. Карта памяти только на FAT16 (объем я так понимаю был только такой в наличии) и FAT32 не работает.
Повторить такое устройство смогут единицы, если захотят (если найдут такие компоненты и будут согласны на программно-аппаратные ограничения).
В итоге, автор сделал классную работу, показал, выяснил, узнал, но для себя. Да я понимаю этот кайф, когда разобрался с какими-то деталями, мелочам, все заработало и на какие-то мелочи даже не обращаешь внимания, потому что сама идея была именно в этом! А про остальные важные моменты забываешь, упускаешь, предполага что это же всё просто, значит люди поймут и разберутся сами... Но это сделают единицы, поймут тоже единицы, а все кто захочет повторить - не смогут...
Это не в упрёк, это взгляд со стороны.
А так, сделать печатную плату, красивый корпус, все укомпоновать, добавить кнопки быстрого доступа к командам, небольшой дисплей и будет изделие
Среди российских программистов-микроконтроллеров в организациях в принципе нет пром-дизайнеров как класса. Хотя факультеты "Промышленного Дизайн" сейчас есть почти в каждом ВУЗзе. Если у нас делают какой-то электронный прибор (пусть даже с хорошей прошивкой), то он похож на кирпич, гробик или шайбу. В качестве корпуса обычно бездумно покупают готовые прямоугольные серые корпуса в ЧипИдип-е. Разъём всегда ставят DB-9 (привет из 195х). Нет уплотнений. щели получаются такие, что между разъёмом и корпусом можно аж палец засунуть. Получившееся изделие даже в руках держать противно. Торчат куски платы об которые можно поцарапаться. Даже если электроника и прошивка вдруг и внезапно получились великолепно, то механическое исполнение продукта все перечеркивает и обнуляет результат на корню.

Автор, я говорил тебе уже, у тебя такой потенциал, а ты каждый раз переизобретаешь велосипед, самокат, колесо и кирпичи.
Спасибо. А что еще остается делать ?
В России не разрабатывают по-настоящему крутую электронную технику.
Негде приложить свои силы.
Не разрабатывают вертикально приземляющиеся ракеты (реактивная посадка), не делают смартфоны, не делают электромобили, не делают радары с синтезом апертуры (SAR локаторы), не делают ЯМРТ томографы. Уровень современной embedded разработки РФ - это, условно, сделать прошивку платы для открытия и закрытия трубы - это максимум. И то с натягом.
И все бы ничего, дальше макетной платы ты не идёшь, почему?
Я специалист по прошивкам. Чертить 3D корпуса не умею. Топологию PCB трассировать тоже. Для того чтобы спроектировать полноценный продукт надо минимум 3 инженера: электронщик, пром-дизайнер и программист.
Статей много, ты делишься информацией, очень круто, а что дальше? Если ты просто хочешь научить всех, показать, как можно делать и что для этого нужно, то хорошо, пусть будет так.
Логика проста.
Российские налогоплательщики финансировали мое бюджетное образование в казёном Политехе. Теперь надо, по возможности, возвращать результаты полученного технического образования обратно в народ.
Хороший труд. Спасибо.

Диктофон на микроконтроллере (WM8731 + I2S + STM32 + SDIO + FAT16)