Перейти к содержанию
    

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

то есть как?

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

 

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

 

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

 

типа так

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

    os_mut_release(bufwr_mutex);
    return len;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

то есть как?

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

 

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

 

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

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

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

Изменено пользователем Atlantis-

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

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

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

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

Изменено пользователем Atlantis-

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

uint8_t* ptr;

uint32_t length;

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Проверенно.

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

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

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...