kan35 7 5 июня, 2023 Опубликовано 5 июня, 2023 · Жалоба Расползание темы в разные дебри не связанные с вопросом я всегда одобряю, так как это однозначно лучше молчания! Спасибо всем гуру. Не знаю, как так уже вышло, но я всегда объявлял массивы строк как char string_received[2][64]; В данном случае при обращении к строкам они лежат друг за другом в памяти, сперва string_received[0], потом string_received[1], каждая по 64. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 133 5 июня, 2023 Опубликовано 5 июня, 2023 · Жалоба 54 минуты назад, kan35 сказал: В данном случае при обращении к строкам они лежат друг за другом в памяти, сперва string_received[0], потом string_received[1], каждая по 64. Вот это меня переклинило, мама дорогая! Да, вы правы, ваш массив объявлен правильно, а мне надо больше спать. Но про передачу массива в функцию по указателю я все написал правильно, так что рассказывайте, как вы определяете, что в функцию передается только два байта строки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xvr 12 5 июня, 2023 Опубликовано 5 июня, 2023 · Жалоба 1 hour ago, kan35 said: Не надо меня подозревать, пожалуйста 🙂 Мне так нужно и я так использую. Тогда объясните, почему именно так. Строки у вас так передаваться не будут - только их адреса, которые всегда одинаковые. Если у вас из очереди данные читаются и обрабатываются всегда быстро (так, что исходный массив не успевает затереться), то работать будет. Но тогда и очередь особенно не нужна 🙂 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Shamil 2 6 июня, 2023 Опубликовано 6 июня, 2023 · Жалоба 10 часов назад, Сергей Борщ сказал: Читайте по губам: строку (которая есть массив символов) невозможно напрямую передать в функцию, вместо массива всегда автоматически передается указатель на этот массив. Спасибо за ликбез конечно. Но я то писал не про передачу строки/указателя в функцию, а про помещение в очередь строки или указателя. Сергей, я безмерно уважаю Вас и Ваш нелегкий труд по подержанию высокого профессионального уровня нашего форума, но в данном случае, Вы никак не улавливаете суть того, о чем я пишу (наверное я плохо объясняю). Попробую еще раз: - Очередь в FreeRTOS огранизована как простой кольцевой буфер, хранящий элементы фиксированного размера. Размер элемента и их максимальное количество задается при создании очереди. - Элементы помещаются в очередь побайтным копированием содержимого элемента в буфер очереди функцией memcpy. Следовательно чтобы поместить в очередь что либо (например указатель на строку, как желает топикстартер), это что то должно располагаться в памяти (чтобы можно было передать указатель на него). Расмотрим на примере того, что желает топикстартер: xQueueTCPRxedString = xQueueCreate( 2, sizeof( char *) ); kan35 создает очередь с максимальным количеством элементов 2, с размером элементов sizeof(char*). Не знаю какой размер указателя на строку в PIC-ах, но будем для определенности считать что 2 байта. char string_received[2][64]; char * data; data = string_received[0]; xQueueSend(xQueueTCPRxedString, &data, 0); Здесь в функцию xQueueSend передается указатель на локальную переменную data, которая содержит значение указателя на строку. Функция xQueueSend копирует 2 байта (т.к. при создании очереди был указан именно такой размер элемента) содержимого переменной data в буфер очереди, при этом в очереди оказывается значение указателя на строку, как и задумывалось. Все работает корректно. Никаких проблем с тем что в функцию передается указатель на локальную переменную не возникает, т.к. этот указатель нигде не запоминается, а используется только значение переменной, на которую он указывает. Теперь другой вариант: xQueueSend(xQueueTCPRxedString, string_received[0], 0); Здесь в функцию xQueueSend передается указатель на саму строку, и происходит копирование 2-х байт самой строки в буфер очереди, на что и жалуется топикстартер. Т.е. явно не то поведение, что требовалось. Вот и собственно и все, о чем я хотел сказать своими сообщениями. Я бы на месте топикстартера, сделал простую функцию-обертку для функции xQueueSend, которая помещала бы в очередь значения передаваемых ей указателей на строку. Что то вроде такого: portBASE_TYPE xQueueSend_My(xQueueHandle xQueue, char * pvItemToQueue, portTickType xTicksToWait) { char *tmpVar = pvItemToQueue; return xQueueSend(xQueue, &tmpVar, xTicksToWait); } Тогда можно будет указывать сразу указатель на строку: xQueueSend_My(xQueueTCPRxedString, string_received[0], 0); Без всяких вспомогательных переменных. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kan35 7 6 июня, 2023 Опубликовано 6 июня, 2023 · Жалоба 9 hours ago, xvr said: Тогда объясните, почему именно так. Строки у вас так передаваться не будут - только их адреса, которые всегда одинаковые. Если у вас из очереди данные читаются и обрабатываются всегда быстро (так, что исходный массив не успевает затереться), то работать будет. Но тогда и очередь особенно не нужна 🙂 Именно, передаются указатели, я же так и написал в самом первом сообщении. Queue - это инструмент, который мне удобен, я передаю сигнал о готовности строки и другая задача просыпается и сразу получает указатель на эту строку. 24 minutes ago, Shamil said: portBASE_TYPE xQueueSend_My(xQueueHandle xQueue, char * pvItemToQueue, portTickType xTicksToWait) { char *tmpVar = pvItemToQueue; return xQueueSend(xQueue, &tmpVar, xTicksToWait); } Тогда можно будет указывать сразу указатель на строку: xQueueSend_My(xQueueTCPRxedString, string_received[0], 0); Без всяких вспомогательных переменных. Обертка в данном случае это наиболее изящное решение, спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 224 6 июня, 2023 Опубликовано 6 июня, 2023 · Жалоба 33 минуты назад, Shamil сказал: Здесь в функцию xQueueSend передается указатель на локальную переменную data, которая содержит значение указателя на строку. Функция xQueueSend копирует 2 байта (т.к. при создании очереди был указан именно такой размер элемента) содержимого переменной data в буфер очереди, при этом в очереди оказывается значение указаталя на строку, как и задумывалось. Все работает корректно. Никаких проблем с тем что в функцию передается указатель на локальную переменную не возникает, т.к. этот указатель нигде не запоминается, а используется только значение переменной, на которую он указывает. А ничего, что сама string_received у ТС возможно - локальная и расположена на стеке и после вызова xQueueSend() возможно сразу же происходит выход из функции? О том, что string_received - глобальная или что после xQueueSend() происходит ожидание окончания использования переданной через очередь строки - нигде ТС не упоминает. PS: Если string_received всё-таки глобальная, то зачем вообще нужен такой громоздкий механизм, как передача указателя на её члены через очередь? Можно сделать гораздо проще. 8 минут назад, kan35 сказал: Queue - это инструмент, который мне удобен, я передаю сигнал о готовности строки и другая задача просыпается и сразу получает указатель на эту строку. Зачем передавать указатели на статический объект (если он всё-таки статический)??? Достаточно передать индекс. А лучше - вообще использовать более простые механизмы синхронизации, а не очередь. Указатель нужно было бы передавать, если бы вы память под свои строки выделяли динамически, из кучи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kan35 7 6 июня, 2023 Опубликовано 6 июня, 2023 · Жалоба string_received это глобальный массив к сожалению и действительно, строки можно было бы передавать индексом в таком случае, но я решил сделать указателем. Это как раз на случай если массив в какой то момент сделаю динамическим. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 133 6 июня, 2023 Опубликовано 6 июня, 2023 · Жалоба 55 минут назад, Shamil сказал: Спасибо за ликбез конечно. Так, ладно, все проржались? А я целых три часа поспал! 55 минут назад, Shamil сказал: Следовательно чтобы поместить в очередь что либо (например указатель на строку, как желает топикстартер), Думаю, все непонятки возникли от того, что kan35 в самом первом сообщении написал 19 часов назад, kan35 сказал: надо передать строку через Queue. Строку, а не указатель на нее. Отсюда и все мои дальнейшие рассуждения о том, что шаманства с указателем - попытки заставить компилятор запихнуть в очередь строку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kan35 7 22 июня, 2023 Опубликовано 22 июня, 2023 · Жалоба Доброго дня всем! Еще один не понятный момент. Указано в справке к порту для PIC18 https://www.freertos.org/a00097.html что код компилятора C18 не реентрантный, в частности по 32 битной математике, и это отдельно решается, ок. В то же время я обнаружил, что стандартные функции типа strtsr, strcpy, memcpy и т д - тоже глючат если их в разных потоках вызывать, что значит, что они тоже не реентратные. Попробовал написать свои функции для работы со строками, и оказалось, что они получаются тоже не реентрантные, в итоге все их заключаю в критические секции и все работает нормально. Конечно использовать критические секции по этому поводу не хотелось бы, так как это потребует снижать скорости по последовательным портам, и накладывать прочие ограничения. Может быть кто сталкивался с такой вот проблемой нереентранности на PIC18 и C18 и есть какие-нибудь изящные решения... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 165 23 июня, 2023 Опубликовано 23 июня, 2023 · Жалоба 10 часов назад, kan35 сказал: тоже глючат если их в разных потоках вызывать, что значит, что они тоже не реентратные... Реентерабельность != потокобезопасности, хоть и тесно соприкасаются. Ваши функции в первую очередь не потокобезопасны. Цитата Конечно использовать критические секции по этому поводу не хотелось бы, так как это потребует снижать скорости по последовательным портам, и накладывать прочие ограничения. Включать режим джедая + оптимизировать длину критических секций. Зачастую бывает так, что потокобезопасным нужно сделать небольшой фрагмент кода, на что обычно забивают и покрывают секцией всю функцию / модуль. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kan35 7 24 июня, 2023 Опубликовано 24 июня, 2023 · Жалоба Да, режим джедая это конечно хорошо, но все таки хотелось бы победить его, а не как сейчас - он победил меня. Вот, например мои утилиты работы со строками в карте памяти: .udata_string_my.o udata 0x000dae data 0x000000 .idata_string_my.o idata 0x000dae data 0x000000 то есть не занимают память вне стека. И вот так выглядит функция, которая "ошибается" при сравнении строк (если без критических секций): unsigned char strings_strcmpram2pgm (const char * str_pgm, rom const char * str_ram) { unsigned int ptr = 0; STRINGS_ENTER_CRITICAL(); while (str_pgm[ptr] == str_ram[ptr] && str_ram[ptr] != 0) { ptr++; } if (ptr && str_pgm[ptr] == str_ram[ptr] && str_ram[ptr] == 0) { STRINGS_EXIT_CRITICAL(); return 0; } STRINGS_EXIT_CRITICAL(); return 1; } (другие функции тоже ошибаются если что). В общем - что тут криминального, чего ему не хватает то - просто даже любопытно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
HardEgor 75 24 июня, 2023 Опубликовано 24 июня, 2023 · Жалоба 1 час назад, kan35 сказал: Да, режим джедая это конечно хорошо, но все таки хотелось бы победить его, а не как сейчас - он победил меня. https://ru.wikipedia.org/wiki/Реентерабельность Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kan35 7 25 июня, 2023 Опубликовано 25 июня, 2023 (изменено) · Жалоба Похоже я нашел таки проблему! И она в недостаточно подробной справке к порту или точнее недоисследованности ситуации с математикой. Quote Memory areas used by the compiler The MPLAB compiler does not generate reentrant code. In particular it uses memory areas as scratch memory when performing mathematical operations. These memory areas are saved by the RTOS kernel as part of the context of each task to ensure re-entrancy. The amount of RAM saved within the context of a task is set by the macro portCOMPILER_MANAGED_MEMORY_SIZE within Source/portable/MPLAB/PIC18F/port.c. After building an application, check the size of the .tmpdata and MATH_DATA sections within the map file. If these total more than 19 bytes the constant portCOMPILER_MANAGED_MEMORY_SIZE and the macros portSAVE_CONTEXT and portRESTORE_CONTEXT will have to be modified accordingly. It is not clear whether this data block will always be of fixed size, or be application specific. Да, я посмотрел в карте памяти MATH_DATA udata 0x000000 data 0x000010 .tmpdata udata 0x000010 data 0x00000c В моем случае сумма не 19 байт, а 28. И я как честный человек поменял portCOMPILER_MANAGED_MEMORY_SIZE с 19 на 28. И решил я поискать где этот макрос используется, обнаружил- что нигде кроме резервирования памяти и вот полез я в port.c. /* Store the .tempdata and MATH_DATA areas as described above. */ \ CLRF FSR0L, 0 \ CLRF FSR0H, 0 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF POSTINC0, PREINC1 \ MOVFF INDF0, PREINC1 \ MOVFF FSR0L, PREINC1 \ MOVFF FSR0H, PREINC1 \ Не разумею я этот птичий язык, но понимаю, что MOVFF POSTINC0, PREINC1 делается 19 раз, соответсвенно делалось и на Restore. Поэтому, добавил еще 9 строк MOVFF POSTINC0, PREINC1 и 9 строк соответственно в MOVFF POSTDEC1, POSTDEC0 И таким образом я наконец то, я надеюсь, что сохраняю и восстанавливаю математический контекст как надо! Надеюсь, ком нибудь будет полезно. Изменено 25 июня, 2023 пользователем kan35 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться