Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.117.186.92] |
|
Сообщ.
#1
,
|
|
|
Всем привет!
Столкнулся с проблемой, а опыта и знаний в данной области не хватает даже для того чтобы понять какую литературу и справочники надо смотреть. Поясню подробно. Есть схема на базе STM32F100RB. Сама схема содержит микрофон, звук с которого цифруется и подаётся на lan порт ПК. Исходник с воспроизведением тонового сигнала: #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include <stm32f10x_adc.h> #include "lan.h" #include "counter.h" #include "web_if.h" #include "ntp.h" static volatile uint16_t ms_count; //static volatile uint32_t second_count; static volatile uint32_t ntp_next_update; static volatile uint32_t time_offset; #define NTP_SERVER inet_addr(192,168,0,11) #define TIMEZONE 7 #define BUFF_MAX 240 int i,j,count =0, k=0; int buff_size = BUFF_MAX; uint16_t val[BUFF_MAX]; uint8_t flag_ADC = 1; uint16_t sin[240] = {0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024, 0, 1024, 2048, 3072, 4095, 3072, 2048, 1024 }; GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; void GPIO_init (void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 ; // two LED (guess on what pin!!) GPIO_Init(GPIOC, &GPIO_InitStructure); // input of ADC (it doesn't seem to be needed, as default GPIO state is floating input) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4; // that's ADC1 (PA1 on STM32) GPIO_Init(GPIOA, &GPIO_InitStructure); } void ADC_init (void){ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // define ADC config ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // we work in continuous sampling mode ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 1,ADC_SampleTime_28Cycles5); // define regular conversion config ADC_Init ( ADC1, &ADC_InitStructure); //set config of ADC1 ADC_Cmd (ADC1,ENABLE); //enable ADC1 // ADC calibration (optional, but recommended at power on) ADC_ResetCalibration(ADC1); // Reset previous calibration while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); // Start new calibration (ADC must be off at that time) while(ADC_GetCalibrationStatus(ADC1)); // start conversion ADC_Cmd (ADC1,ENABLE); //enable ADC1 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // start conversion (will be endless as we are in continuous mode) ADC1->CR2 |= ADC_CR2_ADON; // запуск преобразования } void TIM_init(void){ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE); TIM6->PSC = 0; TIM7->PSC = 0; TIM6->ARR = 3000; TIM7->ARR = 3000; TIM6->DIER |= TIM_DIER_UIE; //разрешаем прерывание от таймера TIM7->DIER |= TIM_DIER_UIE; //разрешаем прерывание от таймера TIM6->CR1 |= TIM_CR1_CEN; // Начать отсчёт! TIM7->CR1 |= TIM_CR1_CEN; // Начать отсчёт! NVIC_EnableIRQ(TIM6_DAC_IRQn); //Разрешение TIM6_DAC_IRQn прерывания NVIC_EnableIRQ(TIM7_IRQn); //Разрешение TIM7_IRQn прерывания RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE); DAC->CR |= DAC_CR_EN1; } void udp_packet(eth_frame_t *frame, uint16_t len) { ip_packet_t *ip = (void*)(frame->data); udp_packet_t *udp = (void*)(ip->data); uint32_t timestamp; if(udp->to_port == NTP_LOCAL_PORT) { if((timestamp = ntp_parse_reply(udp->data, len))) { time_offset = timestamp - second_count; ntp_next_update = second_count + 12UL*60*60; GPIO_SetBits(GPIOC, GPIO_Pin_9); } } } uint8_t tcp_listen(uint8_t id, eth_frame_t *frame) { ip_packet_t *ip = (void*)(frame->data); tcp_packet_t *tcp = (void*)(ip->data); if( (tcp->to_port == htons(80)) || (tcp->to_port == htons(44444)) ) { return 1; } return 0; } void tcp_opened(uint8_t id, eth_frame_t *frame) { } void tcp_closed(uint8_t id, uint8_t reset) { } void tcp_data(uint8_t id, eth_frame_t *frame, uint16_t len, uint8_t closing) { webif_data(id, frame, len); } int main(void) { // int a =0; // uint32_t loctime; //uint8_t s, m, h; GPIO_init(); ADC_init (); TIM_init(); lan_init(); counter_init(); webif_init(); GPIO_SetBits(GPIOC, GPIO_Pin_8); GPIO_ResetBits(GPIOC, GPIO_Pin_8); while(1) { lan_poll(); if(lan_up()) { GPIO_SetBits(GPIOC, GPIO_Pin_8); ntp_request(NTP_SERVER, sin); } else { GPIO_ResetBits(GPIOC, GPIO_Pin_8); } //if (!flag_ADC) { //ntp_request(NTP_SERVER, sin); //flag_ADC = 1; //} //ntp_request(NTP_SERVER); /*if(second_count >= ntp_next_update) { if(!ntp_request(NTP_SERVER)) ntp_next_update = second_count+2; else ntp_next_update = second_count+2; }*/ //loctime = time_offset+second_count + 60UL*60*TIMEZONE; } return 0; } /*Обработчик прерывания от таймера 6 */ void TIM6_DAC_IRQHandler(void) { TIM6->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF //if (count<buff_size){ //DAC->CR &= ~DAC_CR_EN1; //ADC1->CR2 |= ADC_CR2_ADON; // запуск преобразования //while (!(ADC1->SR & ADC_SR_EOC)); // ждем конца преобразования //val[count++] = ADC_GetConversionValue(ADC1); //} //else { //ADC1->CR2 &= ~ADC_CR2_ADON; //DAC->CR |= DAC_CR_EN1; DAC->DHR12R1 = sin[k++]; //10; //DAC->DHR12R1 = val[k++]/10; //} //else DAC->DHR12R1 = sin[k++]; //DAC->DHR12R1 = val[k++]; if (k == buff_size){ k = 0; } //sin[i++]; //Запихиваем в ЦАП очередной элемент массива //if (i==8) i=0; //Если вывели в ЦАП все 32 значения то начинаем заново } /*Обработчик прерывания от таймера 6 */ void TIM7_IRQHandler(void) { TIM7->SR &= ~TIM_SR_UIF; //Сбрасываем флаг UIF val[count++] = ADC_GetConversionValue(ADC1); if (count == buff_size){ //ntp_request(NTP_SERVER, val); flag_ADC = 0; count = 0; } } Контроллер, как мне объяснили, работает в 12 битном режиме. То есть, как я это понимаю, используется Int16 число, но, по 4 из 16 битам выравнивается нулями и лишь 12 бит содержат информацию. Сам контроллер работает как часы - свой звук считывает, воспроизводит, передаёт. Приложение клиента (ПК) так же, сам свой формат читает, воспроизводит, передаёт. Параметры которые я читаю компьютером шарпом: private int samplesPerSecond = 8000; private int bitPerSecond = 16; private int channels = 1; private int bufferSize = 200; По сути я читаю Int16 - для этого просто последовательно извлекаю byte[] из 2 элементов. Наколякал мини "осцилограф" на шарпе - всё прекрасно показывает (на стороне компьютера). Приступаю к тесту - получаю дикие помехи. Пакеты с контроллера доходят на клиент. Клиент их успешно отображает , воспроизводит, но: 1. звук на порядок ниже по тону (это, как я понял, связанно с тем, что я оперирую числами на 16 бит, это в диапозоне 0...65536, а контроллер, работает с 12 битами, что можно представить диапазоном 0...4096 - была идея "размазать" амплитуду домножая каждую величину на отношение 65536/4096, но, боюсь что с голосом такое не прокатит...). 2. появляются пробелы, звук входит порциями, и динамик хрипит потом молчит (как я понял, это связанно с длинной буфера?) 3. я так и не услышал никакого голоса на ПК когда говорю в контроллер. Может ли это быть связанно с настолько сильными искажениями и занижением тона, что сигнал есть, а я его просто не слышу? Или не факт, и сигнала может действительно не быть? Тогда что я не так расшифровываю? (по сути, просто передаю точку как UInt16, получаю точку как byte[] длинной 2) Ни в какие кодировки, преобразования и кодеки пока не влазил, всё в чистом wave без сжатия! Прикрепляю код, который насишарпил. Прикреплённый файлWavUDP.rar (663,77 Кбайт, скачиваний: 245) |
Сообщ.
#2
,
|
|
|
Цитата звук на порядок ниже по тону Не угадал частоту дискретизации(?) Цитата По сути я читаю Int16 - для этого просто последовательно извлекаю byte[] из 2 элементов. Скажи в микрофон "стодвадцатьпять_стодвадцатьшесть_стодвадцатьсемь", залей сырые данных куда-нибудь. |
Сообщ.
#3
,
|
|
|
Цитата Скажи в микрофон "стодвадцатьпять_стодвадцатьшесть_стодвадцатьсемь", залей сырые данных куда-нибудь. До ночи разбирался (заметил что файлик то у меня формируется черезчур маленький!! а там wav без зжатия, и по всем прикидкам, даже с хреновым качеством, фраза "стодвадцатьпять_стодвадцатьшесть_стодвадцатьсемь" ну уж никак не могла весить 200-240 БАЙТ) В общем, нашёл небольшую ошибку... по протоколу udp контроллер отсылал буфер в 1024 байт, а я вижу сторонним софтом, что приходит пакет 60 байт. (Это исправил) Постараюсь как можно быстрее сделать правильную запись. Так же, пытаюсь передать тоновый сигнал, который мифическим образом, появляется раз в 10-18 секунд на 0,1 секунды, хотя контроллер шлёт его непрерывно... куда уходит больше 99% информации даже ума не приложу Насчёт сети: есть роутер, он пробрасывает порты для компов (их несколько) и выдаёт адрес контроллеру. Самое интересное, если бы я просто терял данные, мог бы винить неполадки сети или роутера, но, данные то приходят! Просто они вообще не имеют отношения к звуковой информации (либо, сильнейшие шумы, хотя, отправляю то синусоиду тонового сигнала...) Ещё, есть предположение, что я неправильно читаю два байта от uint16 - может ли быть такое, что я переставляю их местами? Как они вообще должны себя вести у сишного uint16? Например, в шарпе я формирую сообщение на компе, где слева старший байт со старшими битами, справа - младший байт с младшими битами: 1024 = 04 00 могут ли быть такие варианты декодирования 1024: 00 04? (перестановка байт) 00 01? (перестановка байт и бит) 01 00? (перестановка бит) |
Сообщ.
#4
,
|
|
|
Цитата Ещё, есть предположение, что я неправильно читаю два байта от uint16 - может ли быть такое, что я переставляю их местами? Как они вообще должны себя вести у сишного uint16? Ещё может быть выравнивание данных влево и вправо(судя по коду, контроллер использует выравнивание вправо, т.е., значащими являются младшие 12 бит), причём "неиспользуемые" биты могуть быть как нулевыми так и забиты некой служебной инфой. Если удасться получить нормальный поток аудиоданных с устройства, возможно, проблема с форматом решится "автоматически", т.е., будет там int16 без ньюансов. Если нет, залейте потом куда-нибудь и скиньте ссылку. Мне проще разбираться с форматом присылаемых данных, чем искать причину, почему программа не работает. Цитата Постараюсь как можно быстрее сделать правильную запись. Так же, пытаюсь передать тоновый сигнал, который мифическим образом, появляется раз в 10-18 секунд на 0,1 секунды, хотя контроллер шлёт его непрерывно... куда уходит больше 99% информации даже ума не приложу Судя по вашему описанию, проблема пока не столько в формате данных, сколько в неработоспоспособности программы в целом... |
Сообщ.
#5
,
|
|
|
Основная проблема, как выяснилось, была в том, что у контроллера в реализации протокола была допущена ошибка! (фрейм пакета формировался с избытком информации). Отсюда, почти половина данных wav потока - одни и те же бинарные данные, связанные с заголовком пакета . Из-за всего этого и были непонятные "звуки". В целом качество передаваемой волны оставляет желать лучшего, но в асинхронном режиме, всё работает более менее сносно. Правда, такой контроллер спустя время начинает захлёбываться в трафике. В синхронном режиме работы:
0. Контроллер копит порцию данных. 1. Контроллер отправляет данные серверу. 2. Контроллер копит данные. 3. Сервер читает входные данные. 4. Данные заносятся в очередь. 5. Сервер отсылает свою порцию данных контроллеру. 6. Сервер копит данные + переходит в пункт 1 Сервер воспроизводит накопленный буфер, для меня задержка в 1-2 сек. не существенна. Но, возникает непонятная ошибка (это ошибка не по теме, связная с моим криворуким программированием на шарпе) - чем больше очередь данных у сервера, тем медленней идёт воспроизведение, создаётся эффект замедленного воспроизведения (тон понижается незаметно, но во времени растягивается ооочень сильно, 1 сек. может длится от 5 сек. до нескольких минут.). Использую List<byte>, насколько знаю, коллекции достаточно быстрые. Для воспроизведения - создаю поток, преобразую часть коллекции в массив (буквально 1Кб. не больше), и в потоке воспроизвожу байтовый массив на колонки. Контроллер всё успевает воспроизвести и отослать без всяких замедлений и задержек. Так что, основная проблема решилась и вопрос тоже). Большое спасибо за помощь) |
Сообщ.
#6
,
|
|
|
я бы сразу в массив сбрасывал на сервере, и воспроизводил. Там просто с указателями чтения и записи нужно правильно все сделать. А сервер на чем написан?
|
Сообщ.
#7
,
|
|
|
Цитата я бы сразу в массив сбрасывал на сервере, и воспроизводил. я прикреплял исходник, всё так и реализованно) Цитата А сервер на чем написан? C# |
Сообщ.
#8
,
|
|
|
А это где, на контроллере?
Цитата VisualProg @ Использую List<byte>, насколько знаю, коллекции достаточно быстрые. |
Сообщ.
#9
,
|
|
|
Цитата DIS @ А это где, на контроллере? сервер это. Контроллер на сях. Поясню. Мне приходит массив байт. Я его добавляю в буфер List<byte>, далее, сюжет идёт по двум сценариям: 1. Если буфер достаточно большой (около 512 байт) - создаётся поток и всё пускается на воспроизведение 2. Если буфер менее 512 байт - сервер ждёт следующую порцию данных Для чего это сделано - физически, я не могу ускорить работу контроллера, а он, не могёт выдавать информацию с большЕй скоростью, если я воспроизвожу полученные 128-256 байт - буфер очищатся быстрее чем приходит следующая порция данных. Получаю постоянные "отсечки" или пробелы. Поэтому коплю данные в необходимом объёме. Или я что то не так делаю? Просто других решений не придумал |