реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Передача данных, fifo, кольцевой буфер и т.д.
toweroff
сообщение Dec 14 2016, 18:19
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



Цитата(Atlantis- @ Dec 14 2016, 15:40) *
Не совсем понял, как их использовать в моем случае?

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

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

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

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

    os_mut_release(bufwr_mutex);
    return len;
}
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 14 2016, 22:44
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Atlantis- @ Dec 12 2016, 17:43) *
Мне нужен некий буфер для обмена данными между прерываниями (в одном пишу в буфер, в другом читаю, передаю дальше) с условием, что при чтении данные должны лежать в памяти линейно.

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



--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 15 2016, 06:46
Сообщение #18


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Atlantis-
сообщение Dec 15 2016, 07:35
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102



Цитата(zltigo @ Dec 15 2016, 01:44) *
Элементарно. Организовать кольцевой буфер не из байтов, а из блоков данных типового размера.

Эмм...и что будет? У меня сейчас кольцевой буфер 64 байта, а блоки данных 8 байт. Это не мешает одному блоку данных находиться в конце буфера, а второму - в начале.
Цитата(Сергей Борщ @ Dec 15 2016, 09:46) *
Простите, а что мешает при переходе через конец буфера первой посылкой отправлять данные от текущего положения до конца буфера, а по следующему запросу отдавать уже от начала буфера? Я так в УАСПП через ПДП отправляю и VCP у меня так же работает.

Я сначала отмел этот вариант потому что скорость передачи данных по Interrupt каналу и так всего 64 байта за 1 мс. Потом прикинул, вроде должно хватать, получается это более выгодный вариант, чем копировать в линейный буфер.
Но меня сейчас больше волнует, как писать в кольцевой буфер из основного потока и из прерывания одновременно.
Цитата(toweroff @ Dec 14 2016, 21:19) *
то есть как?
функция, которая пишет в буфер, все используют только ее

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

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

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

Сообщение отредактировал Atlantis- - Dec 15 2016, 07:57
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Dec 15 2016, 08:28
Сообщение #20


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Цитата(Atlantis- @ Dec 15 2016, 10:35) *
как писать в кольцевой буфер из основного потока и из прерывания одновременно.

Запрещать прерывание во время работы с буфером из основного приложения. Но это некрасиво.
Цитата(Atlantis- @ Dec 15 2016, 10:35) *
То есть получается надо внутри прерывания I2S буферизировать сообщения...

Разделите свой драйвер I2S на две части: обработчик прерывания и фоновый обработчик на уровне приложения. Фоновый обработчик драйвера I2S будет через небольшой буфер получать данные из обработчика прерывания, а затем формировать и передавать сообщения в вашу общую очередь, доступ к которой вы осуществляете мьютексом. Это позволит вам не блокировать прерывания (не терять данные) и разграничить доступ. Однако следует корректно рассчитать размеры буферов и очередей, а также времена блокировки обработчиков во время обращения за доступом к мьютексу.
Go to the top of the page
 
+Quote Post
Atlantis-
сообщение Dec 15 2016, 11:52
Сообщение #21


Местный
***

Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102



Цитата(Valentine Loginov @ Dec 15 2016, 11:28) *
Запрещать прерывание во время работы с буфером из основного приложения. Но это некрасиво.

Джиттер будет если надолго запрещать
Цитата(Valentine Loginov @ Dec 15 2016, 11:28) *
Разделите свой драйвер I2S на две части: обработчик прерывания и фоновый обработчик на уровне приложения. Фоновый обработчик драйвера I2S будет через небольшой буфер получать данные из обработчика прерывания, а затем формировать и передавать сообщения в вашу общую очередь, доступ к которой вы осуществляете мьютексом. Это позволит вам не блокировать прерывания (не терять данные) и разграничить доступ. Однако следует корректно рассчитать размеры буферов и очередей, а также времена блокировки обработчиков во время обращения за доступом к мьютексу.

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

Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 15 2016, 13:08
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Atlantis- @ Dec 15 2016, 09:35) *
Эмм...и что будет? У меня сейчас кольцевой буфер 64 байта, а блоки данных 8 байт. Это не мешает одному блоку данных находиться в конце буфера, а второму - в начале.

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Dec 15 2016, 13:24
Сообщение #23


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Atlantis- @ Dec 15 2016, 13:52) *
Но I2S у меня работает на частоте 48 кГц, то есть период 21 мкс, прерывание I2S обрабатывается у меня за 3 мкс, а вызов задачи FreeRTOS занимает 4 мкс!


Выглядит не очень разумно каждый сэмпл на I2S делать прерывание.
Но даже так, 3 мкс на прерывание в котором только пересылка это подозрительно много. Может прерывание RTOS используете?
Go to the top of the page
 
+Quote Post
Atlantis-
сообщение Dec 15 2016, 13:26
Сообщение #24


Местный
***

Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102



Цитата(zltigo @ Dec 15 2016, 16:08) *
Не понял о чем Вы написали, и в чем тогда проблема, но 8 байтовые блоки укладываются в 64 байта без перехода за границу блока. Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

Допустим я в этот буфер записал и считал 7 таких сообщений, указатель записи у меня равен 56. И вот пишу я одно сообщение (указатель записи = 0), а потом второе (указатель записи равен 8). После этого возникает прерывание на чтение данных, а данные в памяти расположены прерывисто.
И я не могу после передачи данных сбрасывать указатель записи в ноль, потому что у прерывания, которое пишет в буфер приоритет выше, чем у прерывания, которое из буфера читает.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 15 2016, 13:30
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



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

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Atlantis-
сообщение Dec 15 2016, 14:03
Сообщение #26


Местный
***

Группа: Участник
Сообщений: 491
Регистрация: 18-05-11
Пользователь №: 65 102



Цитата(AlexandrY @ Dec 15 2016, 16:24) *
Выглядит не очень разумно каждый сэмпл на I2S делать прерывание.

Согласен, но я не нашел другого способа. Мне нужно выдавать в I2S данные из памяти, а потом делать паузу (слать нули). Данные я могу через DMA слать, а паузу уже нет - она может быть большой, памяти не хватит.
Цитата(AlexandrY @ Dec 15 2016, 16:24) *
Но даже так, 3 мкс на прерывание в котором только пересылка это подозрительно много. Может прерывание RTOS используете?

Почему много? У меня там куча условных операторов, которые контролируют разные счетчики и данные читаются из внешней памяти SDRAM. Хотя я измерил сколько времени идет на запись 8 байт в буфер и инкремент счетчика записи - получилось 1,3 мкс.
Прерывание RTOS использую, его я тоже замерил - обрабатывается за 2,5 мкс. Но его приоритет - самый низкий.
Цитата(zltigo @ Dec 15 2016, 16:30) *
Читаем внимательно:
Если хотите оперировать (например передавать) большими блоками, то тогда и буфер должен состоять из блоков такого размера

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

Сообщение отредактировал Atlantis- - Dec 15 2016, 14:07
Go to the top of the page
 
+Quote Post
Valentine Logino...
сообщение Dec 16 2016, 08:23
Сообщение #27


Частый гость
**

Группа: Участник
Сообщений: 78
Регистрация: 7-04-10
Из: Пушкино
Пользователь №: 56 462



Цитата(Atlantis- @ Dec 15 2016, 14:52) *
Я хотел так сначала разделить - чтобы прерывание I2S только отправляло данные и обрабатывало флаги, а расчет следующих данных для отправки и всего остального вести в специальной задаче, которую вызывать из прерывания I2S. Но I2S у меня работает на частоте 48 кГц, то есть период 21 мкс, прерывание I2S обрабатывается у меня за 3 мкс, а вызов задачи FreeRTOS занимает 4 мкс! Поэтому я решил все эти дела делать в прерывании, даже для сообщений кольцевой буфер сделал, хотя мог просто очередь создать и писать в нее хоть из прерываний, хоть из основного потока одновременно. Но писать в очередь в прерывании I2S это плюс 4 мкс к времени его обработки, то есть в сумме 7 мкс, а это уже треть от 21...в общем показалось мне многовато, поэтому и пытаюсь что то изобрести.


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

Подозрительно большие числа по временам, особенно на переключение контекста FreeRTOS, это сколько же у вас там задач? Было бы легче, если бы была информация о камне и его тактировании. Те же прерывания нужно оптимизировать грамотными аттрибутами на инлайнинг, оптимизацию и пр.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 16 2016, 08:45
Сообщение #28


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Atlantis- @ Dec 15 2016, 16:03) *
Не понял, что Вы имеете ввиду? Если я хочу передавать блоками максимум по 64 байта, значит мне сделать буфер состоящий из блоков по 64 байта каждый? Не очень представляю как с ним работать.

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
toweroff
сообщение Dec 16 2016, 09:45
Сообщение #29


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



можно вообще сделать кольцо из структур
uint8_t* ptr;
uint32_t length;

при приеме данных выделяем место в куче, записываем указатель и длину блока. Когда обработали блок - освободили память
Go to the top of the page
 
+Quote Post
AlexandrY
сообщение Dec 16 2016, 09:58
Сообщение #30


Ally
******

Группа: Модераторы
Сообщений: 6 232
Регистрация: 19-01-05
Пользователь №: 2 050



Цитата(Atlantis- @ Dec 15 2016, 16:03) *
Согласен, но я не нашел другого способа. Мне нужно выдавать в I2S данные из памяти, а потом делать паузу (слать нули). Данные я могу через DMA слать, а паузу уже нет - она может быть большой, памяти не хватит.


Для этого в STM32 есть Double buffer mode у DMA, в Kinetis это еще красивей можно сделать.
Проверенно.
Параллельно еще есть уйма времени читать SD карту и поддерживать несколько потоков по USB.
Для пауз буфера заполняются нулями за время на порядки меньше чем время воспроизведения буфера.
Эстеты и нулями могут по DMA заполнять.

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

Т.е. тема прерываний I2S вами ни разу не раскрыта. biggrin.gif
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th August 2025 - 12:09
Рейтинг@Mail.ru


Страница сгенерированна за 0.02142 секунд с 7
ELECTRONIX ©2004-2016