Jump to content

    
Sign in to follow this  
Dima1060

Передача данных

Recommended Posts

Не совсем понял, как их использовать в моем случае?

то есть как?

функция, которая пишет в буфер, все используют только ее

 

в начале ждем мютекс, в конце отпускаем

 

если функция вызывается и мютекс занят (кто-то уже вызвал функцию), ОС будет держать вызывающую функцию в ожидании, пока мютекс не освободится (ранее вызвавший функцию записи в буфер закончил работу)

 

типа так

int write_buf(uint8_t *buf, int len)
{
    os_mut_wait(bufwr_mutex, 0xFFFF);
    
// тут пишем в буфер

    os_mut_release(bufwr_mutex);
    return len;
}

Share this post


Link to post
Share on other sites
Мне нужен некий буфер для обмена данными между прерываниями (в одном пишу в буфер, в другом читаю, передаю дальше) с условием, что при чтении данные должны лежать в памяти линейно.

Элементарно. Организовать кольцевой буфер не из байтов, а из блоков данных типового размера.Если блоки данных произвольного размера, то добавить дополнительный указатель позволяющий помечать и соответственно пропускать в конце блока памяти выделенного под кольцевой буфер блок, размер которого недостаточен для размещения полученного блока данных.

 

 

Share this post


Link to post
Share on other sites

Простите, а что мешает при переходе через конец буфера первой посылкой отправлять данные от текущего положения до конца буфера, а по следующему запросу отдавать уже от начала буфера? Я так в УАСПП через ПДП отправляю и VCP у меня так же работает.

Share this post


Link to post
Share on other sites
Элементарно. Организовать кольцевой буфер не из байтов, а из блоков данных типового размера.

Эмм...и что будет? У меня сейчас кольцевой буфер 64 байта, а блоки данных 8 байт. Это не мешает одному блоку данных находиться в конце буфера, а второму - в начале.

Простите, а что мешает при переходе через конец буфера первой посылкой отправлять данные от текущего положения до конца буфера, а по следующему запросу отдавать уже от начала буфера? Я так в УАСПП через ПДП отправляю и VCP у меня так же работает.

Я сначала отмел этот вариант потому что скорость передачи данных по Interrupt каналу и так всего 64 байта за 1 мс. Потом прикинул, вроде должно хватать, получается это более выгодный вариант, чем копировать в линейный буфер.

Но меня сейчас больше волнует, как писать в кольцевой буфер из основного потока и из прерывания одновременно.

то есть как?

функция, которая пишет в буфер, все используют только ее

 

в начале ждем мютекс, в конце отпускаем

 

если функция вызывается и мютекс занят (кто-то уже вызвал функцию), ОС будет держать вызывающую функцию в ожидании, пока мютекс не освободится (ранее вызвавший функцию записи в буфер закончил работу)

Это подразумевает, что пишущий поток должен отложить свою работу на потом. У меня предполагается, что в кольцевой буфер будут писаться сообщения из прерывания I2S о начале/конце выдаваемого блока данных и сообщения из основного потока о нажатии кнопок.

То есть очень вероятен вариант, что я буду писать сообщение в буфер из основного потока, в этот момент вылетит прерывание и данные смешаются. Тут я вроде бы должен заблокировать запись в буфер из прерывания, но когда прерывание снова сработает снова - мне надо будет посылать еще одно сообщение (первое - о конце одного блока данных, второе - о начале другого блока). То есть получается надо внутри прерывания I2S буферизировать сообщения...

Edited by Atlantis-

Share this post


Link to post
Share on other sites
как писать в кольцевой буфер из основного потока и из прерывания одновременно.

Запрещать прерывание во время работы с буфером из основного приложения. Но это некрасиво.

То есть получается надо внутри прерывания I2S буферизировать сообщения...

Разделите свой драйвер I2S на две части: обработчик прерывания и фоновый обработчик на уровне приложения. Фоновый обработчик драйвера I2S будет через небольшой буфер получать данные из обработчика прерывания, а затем формировать и передавать сообщения в вашу общую очередь, доступ к которой вы осуществляете мьютексом. Это позволит вам не блокировать прерывания (не терять данные) и разграничить доступ. Однако следует корректно рассчитать размеры буферов и очередей, а также времена блокировки обработчиков во время обращения за доступом к мьютексу.

 

Share this post


Link to post
Share on other sites
Запрещать прерывание во время работы с буфером из основного приложения. Но это некрасиво.

Джиттер будет если надолго запрещать

Разделите свой драйвер I2S на две части: обработчик прерывания и фоновый обработчик на уровне приложения. Фоновый обработчик драйвера I2S будет через небольшой буфер получать данные из обработчика прерывания, а затем формировать и передавать сообщения в вашу общую очередь, доступ к которой вы осуществляете мьютексом. Это позволит вам не блокировать прерывания (не терять данные) и разграничить доступ. Однако следует корректно рассчитать размеры буферов и очередей, а также времена блокировки обработчиков во время обращения за доступом к мьютексу.

Я хотел так сначала разделить - чтобы прерывание I2S только отправляло данные и обрабатывало флаги, а расчет следующих данных для отправки и всего остального вести в специальной задаче, которую вызывать из прерывания I2S. Но I2S у меня работает на частоте 48 кГц, то есть период 21 мкс, прерывание I2S обрабатывается у меня за 3 мкс, а вызов задачи FreeRTOS занимает 4 мкс! Поэтому я решил все эти дела делать в прерывании, даже для сообщений кольцевой буфер сделал, хотя мог просто очередь создать и писать в нее хоть из прерываний, хоть из основного потока одновременно. Но писать в очередь в прерывании I2S это плюс 4 мкс к времени его обработки, то есть в сумме 7 мкс, а это уже треть от 21...в общем показалось мне многовато, поэтому и пытаюсь что то изобрести.

 

 

Share this post


Link to post
Share on other sites
Эмм...и что будет? У меня сейчас кольцевой буфер 64 байта, а блоки данных 8 байт. Это не мешает одному блоку данных находиться в конце буфера, а второму - в начале.

Не понял о чем Вы написали, и в чем тогда проблема, но 8 байтовые блоки укладываются в 64 байта без перехода за границу блока. Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

 

Share this post


Link to post
Share on other sites
Но I2S у меня работает на частоте 48 кГц, то есть период 21 мкс, прерывание I2S обрабатывается у меня за 3 мкс, а вызов задачи FreeRTOS занимает 4 мкс!

 

Выглядит не очень разумно каждый сэмпл на I2S делать прерывание.

Но даже так, 3 мкс на прерывание в котором только пересылка это подозрительно много. Может прерывание RTOS используете?

Share this post


Link to post
Share on other sites
Не понял о чем Вы написали, и в чем тогда проблема, но 8 байтовые блоки укладываются в 64 байта без перехода за границу блока. Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

Допустим я в этот буфер записал и считал 7 таких сообщений, указатель записи у меня равен 56. И вот пишу я одно сообщение (указатель записи = 0), а потом второе (указатель записи равен 8). После этого возникает прерывание на чтение данных, а данные в памяти расположены прерывисто.

И я не могу после передачи данных сбрасывать указатель записи в ноль, потому что у прерывания, которое пишет в буфер приоритет выше, чем у прерывания, которое из буфера читает.

Share this post


Link to post
Share on other sites
Допустим я в этот буфер записал и считал 7 таких сообщений, указатель записи у меня равен 56. И вот пишу я одно сообщение (указатель записи = 0), а потом второе (указатель записи равен 8). После этого возникает прерывание на чтение данных, а данные в памяти расположены прерывисто.

И я не могу после передачи данных сбрасывать указатель записи в ноль, потому что у прерывания, которое пишет в буфер приоритет выше, чем у прерывания, которое из буфера читает.

Читаем внимательно:

Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

Share this post


Link to post
Share on other sites
Выглядит не очень разумно каждый сэмпл на I2S делать прерывание.

Согласен, но я не нашел другого способа. Мне нужно выдавать в I2S данные из памяти, а потом делать паузу (слать нули). Данные я могу через DMA слать, а паузу уже нет - она может быть большой, памяти не хватит.

Но даже так, 3 мкс на прерывание в котором только пересылка это подозрительно много. Может прерывание RTOS используете?

Почему много? У меня там куча условных операторов, которые контролируют разные счетчики и данные читаются из внешней памяти SDRAM. Хотя я измерил сколько времени идет на запись 8 байт в буфер и инкремент счетчика записи - получилось 1,3 мкс.

Прерывание RTOS использую, его я тоже замерил - обрабатывается за 2,5 мкс. Но его приоритет - самый низкий.

Читаем внимательно:

Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

Не понял, что Вы имеете ввиду? Если я хочу передавать блоками максимум по 64 байта, значит мне сделать буфер состоящий из блоков по 64 байта каждый? Не очень представляю как с ним работать.

Edited by Atlantis-

Share this post


Link to post
Share on other sites
Я хотел так сначала разделить - чтобы прерывание I2S только отправляло данные и обрабатывало флаги, а расчет следующих данных для отправки и всего остального вести в специальной задаче, которую вызывать из прерывания I2S. Но I2S у меня работает на частоте 48 кГц, то есть период 21 мкс, прерывание I2S обрабатывается у меня за 3 мкс, а вызов задачи FreeRTOS занимает 4 мкс! Поэтому я решил все эти дела делать в прерывании, даже для сообщений кольцевой буфер сделал, хотя мог просто очередь создать и писать в нее хоть из прерываний, хоть из основного потока одновременно. Но писать в очередь в прерывании I2S это плюс 4 мкс к времени его обработки, то есть в сумме 7 мкс, а это уже треть от 21...в общем показалось мне многовато, поэтому и пытаюсь что то изобрести.

 

Тут вам в помощь счётный семафор. Не обязательно же чтобы на каждый вызов прерывания немедленно запускалась задача обработки, главное чтобы данные не потерялись.

 

Подозрительно большие числа по временам, особенно на переключение контекста FreeRTOS, это сколько же у вас там задач? Было бы легче, если бы была информация о камне и его тактировании. Те же прерывания нужно оптимизировать грамотными аттрибутами на инлайнинг, оптимизацию и пр.

Share this post


Link to post
Share on other sites
Не понял, что Вы имеете ввиду? Если я хочу передавать блоками максимум по 64 байта, значит мне сделать буфер состоящий из блоков по 64 байта каждый? Не очень представляю как с ним работать.

Так же, как и с буфером из какого то количества байт, только вместо одного байта - 64 и указатель указывает не на байт в буфере, а на блок.

Share this post


Link to post
Share on other sites

можно вообще сделать кольцо из структур

uint8_t* ptr;

uint32_t length;

 

при приеме данных выделяем место в куче, записываем указатель и длину блока. Когда обработали блок - освободили память

Share this post


Link to post
Share on other sites
Согласен, но я не нашел другого способа. Мне нужно выдавать в I2S данные из памяти, а потом делать паузу (слать нули). Данные я могу через DMA слать, а паузу уже нет - она может быть большой, памяти не хватит.

 

Для этого в STM32 есть Double buffer mode у DMA, в Kinetis это еще красивей можно сделать.

Проверенно.

Параллельно еще есть уйма времени читать SD карту и поддерживать несколько потоков по USB.

Для пауз буфера заполняются нулями за время на порядки меньше чем время воспроизведения буфера.

Эстеты и нулями могут по DMA заполнять.

 

Короче, в прерываниях от I2S я ни разу не видел необходимости.

 

Т.е. тема прерываний I2S вами ни разу не раскрыта. :biggrin:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this