|
|
  |
Организация программ, дайте вектор куда копать |
|
|
|
Mar 31 2017, 07:52
|
Знающий
   
Группа: Участник
Сообщений: 634
Регистрация: 27-10-10
Пользователь №: 60 464

|
Планируется разработка измерительного прибора, принимающего данные от АЦП в прерывании, складывающего данные в буфер и обрабатывающего данные пос ложному алгоритму. Дело в том что нужно часто давать сигналы готовности данных на разных ступенях алгоритма. Использовать флаги - глобальные переменные неудобно (их будет слишком много). Сообщить, какие "более красивые подходы" для этого используются. например на микрокотнтроллере можно использовать ОСРВ и ее средства взаимодействия между задачами, а как быть когда нужно сделать демо-проект на PC (для последующего переноса на МК)?
Например есть такая задача: 1)АЦП складывает данные непрерывно в кольцевой буфер 2) Раз в миллисекунду данные из буфера обрабатываются результат сохраняется в переменную. 3) после 10й итерации по пункту 2 (т.е. раз в 10 миллисекунд) нужно делать усреднение данных
У меня сейчас в функции, которая реализует п.2 просто есть счетчик итераций в виде переменной. Я опрашиваю эту переменную, и, как только она равна 10 - запускаю функию, реализующую п.3 Все это выглядит ужасно в бесконечном цикле.
Подскажите, как сделать грамотно.
Сообщение отредактировал Zelepuk - Mar 31 2017, 08:00
|
|
|
|
|
Mar 31 2017, 08:24
|
Знающий
   
Группа: Участник
Сообщений: 634
Регистрация: 27-10-10
Пользователь №: 60 464

|
Цитата(ViKo @ Mar 31 2017, 11:19)  Я понял так, программа делает то, что от нее требуется. Кому какое дело, как она устроена? Кроме разработчика,желающего сделать красиво. Так и сделайте, как считаете. Сравните. Переделайте еще 5 раз. Нормальный процесс. Эт понятно. мне интересно как можно считать. На уме был только суперлуп...  но есть понимание что тогда прога будет изобиловать глобальными переменными. Я про подходы говорю. Интересно как можно сделать. Вот статья в тему интересная: https://habrahabr.ru/post/148805/ Я вот например хочу сделать на FreeRTOS, но как тогда удобно сделать чтобы проект запустился и на PC. На PC запускаю для демонстрационных целей.
|
|
|
|
|
Mar 31 2017, 08:52
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Zelepuk @ Mar 31 2017, 09:52)  У меня сейчас в функции, которая реализует п.2 просто есть счетчик итераций в виде переменной. Я опрашиваю эту переменную, и, как только она равна 10 - запускаю функию, реализующую п.3 Подскажите, как сделать грамотно. В ISR, который пишет данные в буфер, смотреть сколько данных накопилось в буфере, и если их больше чем сколько-то - посылать сообщение в майл-бокс. А под ОС есть задача, которая ждёт на этом мэйл-боксе, и получив сообщение, запускается, читает и обрабатывает данные из буфера, до его опустошения. Потом снова идёт на ожидание мэйл-бокса. Это классический подход к реализации задач обработки событий под ОС. И в том числе цикл обработки сообщений винды (основной рабочий цикл любой GUI-программы) так работает. И все задачи работающие с данными из периферии (или генерящие туда данные) у меня так построены.
|
|
|
|
|
Mar 31 2017, 09:09
|

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

|
Цитата(Zelepuk @ Mar 31 2017, 11:24)  Эт понятно. мне интересно как можно считать. На уме был только суперлуп...  но есть понимание что тогда прога будет изобиловать глобальными переменными. Я про подходы говорю. Интересно как можно сделать. Вот статья в тему интересная: https://habrahabr.ru/post/148805/ Я вот например хочу сделать на FreeRTOS, но как тогда удобно сделать чтобы проект запустился и на PC. На PC запускаю для демонстрационных целей. FreeRTOS не лучший выбор. Я бы рекомендовал Micrium OSГораздо быстрее, понятнее и компактнее чем FreeRTOS. Там кстати очень ценная фишка для риалтайма появилась - работа сервисов без запрещения прерываний. Глобальные флаги не так плохи как кажется. Когда у вас появится больше 5-и источников прерываний по 1 мс и около десятка задач, просто чтобы поддерживать все необходимые интерфейсы как вот здесь:
и когда использование процессора подойдет к 80%, то вы быстро поймете, что стоит вместо сервисов RTOS использовать глобальные флаги или иначе потеряете реальное время. Хороший способ - это критичные прерывания сделать прерываниями ядра, и чтобы они выставляли глобальные флаги и софтварно прерывания с сервисами RTOS. Это очень эффективный способ прореживания прерываний PendSV и укорачивания времени выполнения остальных прерываний. Но на PC вы это не перенесете, это все очень архитектурно привязано к железу. Риалтайм в принципе не отладить на PC.
|
|
|
|
|
Mar 31 2017, 09:23
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(AlexandrY @ Mar 31 2017, 11:09)  FreeRTOS не лучший выбор. Я бы рекомендовал Micrium OSГораздо быстрее, понятнее и компактнее чем FreeRTOS. Поддерживаю! Цитата(AlexandrY @ Mar 31 2017, 11:09)  Но на PC вы это не перенесете, это все очень архитектурно привязано к железу. Риалтайм в принципе не отладить на PC. Перенести можно, если разделить на middle-ware и собственно low level IO с периферией. Сам делал и отлаживал так когда сложный драйвер. Из железа ему нужен был только IO с UART. Так что нижний уровень драйвера на МК - это был IO в/из кольцевых буферов в ISR-ах, а на PC - в те же самые буфера в/из файловых функций WinAPI + система сообщений к задаче обработке - мэйл-боксы под Микриум, и соотв. средства синхронизации под винду. Основной код драйвера - выполнялся в виде задачи обработки событий, которая была общая для Win и для Микриум. Очень удобно было отлаживать. Там 95% всего объёма составляло это middle-ware. Да собственно так же организована FatFS. Её тоже можно выполнять под любой ОС хоть под виндой. Написав простую low level IO прослойку.
|
|
|
|
|
Mar 31 2017, 09:55
|
Гуру
     
Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847

|
2 ТС - какой у вас целевой процессор и ресурсы? Если они позволяют развернуться с RTOS и всем, что к ней прилагается (в самом общем смысле), то можно взять что нибудь, что работает и под РС тоже (eCos непример) и написать на ней. Получите то, что хотите - и РС для отладки и МК в качестве конечной цели. Если же с ресурсвми на МК не густо, то перенос чего либо с РС на МК дело непростое - проще сделать слой совместимости и писать поверх него (как вам тут уже советовали). Но это дополнительная работа (и может быть очень не малая  ) Есть промежуточный подход - выделить из задачи блоки, напрямую не зависищие от аппаратуры, написать их отдельными модулями и сделать для них unit тесты (для отладки) Тогда большую (или меньшую, если не повезет  ) часть можно будет отладить на РС, но собирать это все в кучу придется на МК (и run time взаимодествие между модулями тоже придется делать на МК)
|
|
|
|
|
Mar 31 2017, 10:20
|

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

|
Цитата(jcxz @ Mar 31 2017, 12:23)  Перенести можно, если разделить на middle-ware и собственно low level IO с периферией. Micrium OS с самого рождения имела порт по Windows. А нынче у нее под Windows выполняется всё: файловая, сетевые стеки, GUI, USB Весь список виден в Micrium Platform Builder. Но риалтайм ( т.е. как быстро обрабатываются задачи и прерывания и как расходуются ресурсы процессора) это отладить не помогает. На PC я отлаживаю исключительно сторонние программные модули с неизвестным потреблением памяти. Все остальное не оправдано, поскольку такие IDE как IAR с SWD компилируют и загружают на целевую платформу почти с такой же скоростью как и в Visual Studio под Windows
|
|
|
|
|
Mar 31 2017, 10:28
|

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

|
Цитата(Lagman @ Mar 31 2017, 12:42)  Эх, была бы она бесплатная, хотя бы как раньше, купил книгу и используй как хочешь. Хотя после того как micrium был куплен Silicon Labs может и бесплатно уже распространяется? Бесплатная то она бесплатная, но мне только через 2 месяца пришел ответ типа извините мы были перегружены запросами, хотим продолжить общение. И на очередной запрос опять зависли. Цитата(jcxz @ Mar 31 2017, 13:24)  Это да, но под виндой лучше дело с логгированием и сохранением разных отладочных данных (есть файловая система для этого). И это сохранение практически не влияет на работу отлаживаемого кода. RTT через SWD логгирует с той же скоростью и также может писать в файлы. Но главное эти логи можно оставить в релизной версии. Т.е. сорсы не приходится править и захламлять условными препроцессорными директивами. Кстати вот как я тестировал FatFS на целевой платформе - https://geektimes.ru/post/274416/Ну зачем мне там нужно было бы делать это на PC?
|
|
|
|
|
Mar 31 2017, 12:12
|
Знающий
   
Группа: Участник
Сообщений: 634
Регистрация: 27-10-10
Пользователь №: 60 464

|
Цитата(jcxz @ Mar 31 2017, 11:52)  В ISR, который пишет данные в буфер, смотреть сколько данных накопилось в буфере, и если их больше чем сколько-то - посылать сообщение в майл-бокс. А под ОС есть задача, которая ждёт на этом мэйл-боксе... Вот вопрос как это делается, где почитать/посмотреть/скачать пример этого... Цитата(AlexandrY @ Mar 31 2017, 13:20)  Но риалтайм ( т.е. как быстро обрабатываются задачи и прерывания и как расходуются ресурсы процессора) это отладить не помогает. Собственно на PC не нужно отлаживать реалтайм, на PC нужно показать как все это работает. Например вместо считывания данных в прерывании считывать данные из файла. Вопрос только как именно это сделать, если на мк есть прерывание и функциа типа ISR_ADC(), то на PC(в консольном приложении) как имитировать периодический вызов функции чтения из файла?
|
|
|
|
|
Mar 31 2017, 13:47
|
Знающий
   
Группа: Участник
Сообщений: 634
Регистрация: 27-10-10
Пользователь №: 60 464

|
Цитата(syoma @ Mar 31 2017, 16:22)  Zelepuk, а не хотите попробовать Matlab/Simulink/Embedded Coder под это дело? Ваша задача выглядит типовой для этого. Т.е. всю обработку данных и свои алгоритмы нарисовать в Simulink в виде модели, которую вы сможете моделировать на PC вместе с входными данными, а затем всю модель выгрузить за несколько кликов в Си код, который будет исполняться в реальном времени на вашем контроллере. И все это без морок с глобальными флагами и переменными и часто даже без ОСРВ. Это достаточно "красивый" подход с заделом на будущее. Называется Model-Based Design. Почем-то мне думается что там не все так просто и красиво как описывается. посмотреть бы пример реализации такого подхода. Генерируемый код весьма труден для понимания. Увидеть бы готовый вариант простой процедуры: принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс.
|
|
|
|
|
Mar 31 2017, 14:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата Генерируемый код весьма труден для понимания. Его не надо читать и понимать. Достаточно знать, что он делает то же самое, что и в симуляции. Цитата принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс. Вопрос - сколько байт надо накопить за 100мс? или как часто приходят новые данные?
|
|
|
|
|
Mar 31 2017, 14:26
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Zelepuk @ Mar 31 2017, 15:47)  Почем-то мне думается что там не все так просто и красиво как описывается. посмотреть бы пример реализации такого подхода. Генерируемый код весьма труден для понимания. Увидеть бы готовый вариант простой процедуры: принять байт от SPI, накопить буфер, посчитать среднее раз в 100мс. Что там трудного?: CODE void MboxPost(OS_EVENT *mbox) { int e = OSMboxPost(mbox, (void *)1); if (e != OS_ERR_NONE && e != OS_ERR_MBOX_FULL) trap(TRAP_OS, e); } void MboxPend(OS_EVENT *mbox) { u8 e; OSMboxPend(mbox, 0, &e); if (e != OS_ERR_NONE) trap(TRAP_OS, e); } isr() { if (PERIPH.EMPTY) return; t1 = sysTimer; do { //Вычитываем все байты из FIFO периферии в программный FIFO. uint i = PERIPH.READ; if (!FIFO.isFull()) FIFO.write(i); } while (!PERIPH.EMPTY); if (FIFO.cnt() < N) if ((uint)(sysTimer - t1) < (uint)T) return; //Смотрим если в программном FIFO накопилось менее чем N байт (FIFO.cnt) и прошло менее чем T мсек с момента t1, то return; иначе: IsrEnter(); MboxPost(mbox); //посылаем сообщение сервисному процессу обработать накопленный программный FIFO. IsrExit(); } __noreturn void Task(void *) { //сервисный процесс, обслуживающий программный FIFO t1 = sysTimer; while (1) { while (!FIFO.isEmpty()) { FIFO.read(); ... } MboxPend(mbox); } } Всё. Это для uCOS. Для других ОС примерно так же.
|
|
|
|
|
Mar 31 2017, 19:31
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата(Zelepuk @ Mar 31 2017, 16:33)  примерно 50кБ. Если считать, что принять байт от SPI, накопить буфер, - это делает Ваш драйвер SPI, а сама процедура посчитать среднее вызывается раз в 100мс, и ей передается массив из 50000 значений, то в Симулинке она будет выглядеть так:
Рассчитано для исходного типа int8, результата суммы int32. Тогда сгенерированный код будет выглядеть вот так: ert_main.c - функция main CODE /* /* * File: ert_main.c * * Code generated for Simulink model 'Average'. * * Model version : 1.39 * Simulink Coder version : 8.11 (R2016b) 25-Aug-2016 * C/C++ source code generated on : Fri Mar 31 21:32:35 2017 * * Target selection: ert.tlc * Embedded hardware selection: 32-bit Generic * Code generation objectives: Unspecified * Validation result: Not run */
#include <stddef.h> #include <stdio.h> /* This ert_main.c example uses printf/fflush */ #include "Average.h" /* Model's header file */ #include "rtwtypes.h"
static RT_MODEL_Average_T Average_M_; static RT_MODEL_Average_T *const Average_M = &Average_M_;/* Real-time model */
/* '<Root>/In1' */ static int8_T Average_U_In1[50000];
/* '<Root>/Out1' */ static int8_T Average_Y_Out1;
/* * Associating rt_OneStep with a real-time clock or interrupt service routine * is what makes the generated code "real-time". The function rt_OneStep is * always associated with the base rate of the model. Subrates are managed * by the base rate from inside the generated code. Enabling/disabling * interrupts and floating point context switches are target specific. This * example code indicates where these should take place relative to executing * the generated code step function. Overrun behavior should be tailored to * your application needs. This example simply sets an error status in the * real-time model and returns from rt_OneStep. */ void rt_OneStep(RT_MODEL_Average_T *const Average_M); void rt_OneStep(RT_MODEL_Average_T *const Average_M) { static boolean_T OverrunFlag = false;
/* Disable interrupts here */
/* Check for overrun */ if (OverrunFlag) { return; }
OverrunFlag = true;
/* Save FPU context here (if necessary) */ /* Re-enable timer or interrupt here */ /* Set model inputs here */
/* Step the model */ Average_step(Average_M, Average_U_In1, &Average_Y_Out1);
/* Get model outputs here */
/* Indicate task complete */ OverrunFlag = false;
/* Disable interrupts here */ /* Restore FPU context here (if necessary) */ /* Enable interrupts here */ }
/* * The example "main" function illustrates what is required by your * application code to initialize, execute, and terminate the generated code. * Attaching rt_OneStep to a real-time clock is target specific. This example * illustrates how you do this relative to initializing the model. */ int_T main(int_T argc, const char *argv[]) { /* Unused arguments */ (void)(argc); (void)(argv);
/* Pack model data into RTM */
/* Initialize model */ Average_initialize(Average_M, Average_U_In1, &Average_Y_Out1);
/* Attach rt_OneStep to a timer or interrupt service routine with * period 0.1 seconds (the model's base sample time) here. The * call syntax for rt_OneStep is * * rt_OneStep(Average_M); */ printf("Warning: The simulation will run forever. " "Generated ERT main won't simulate model step behavior. " "To change this behavior select the 'MAT-file logging' option.\n"); fflush((NULL)); while (((void*) 0) == (NULL)) { /* Perform other application tasks here */ }
/* The option 'Remove error status field in real-time model data structure' * is selected, therefore the following code does not need to execute. */ #if 0
/* Disable rt_OneStep() here */
/* Terminate model */ Average_terminate(Average_M);
#endif
return 0; }
/* * File trailer for generated code. * * [EOF] */
Функция average - собственно сам расчет среднего CODE /* * File: Average.c * * Code generated for Simulink model 'Average'. * * Model version : 1.39 * Simulink Coder version : 8.11 (R2016b) 25-Aug-2016 * C/C++ source code generated on : Fri Mar 31 21:22:13 2017 * * Target selection: ert.tlc * Embedded hardware selection: 32-bit Generic * Code generation objectives: Unspecified * Validation result: Not run */
#include "Average.h" #include "Average_private.h"
void mul_wide_s32(int32_T in0, int32_T in1, uint32_T *ptrOutBitsHi, uint32_T *ptrOutBitsLo) { uint32_T absIn0; uint32_T absIn1; uint32_T in0Lo; uint32_T in0Hi; uint32_T in1Hi; uint32_T productHiLo; uint32_T productLoHi; absIn0 = in0 < 0 ? ~(uint32_T)in0 + 1U : (uint32_T)in0; absIn1 = in1 < 0 ? ~(uint32_T)in1 + 1U : (uint32_T)in1; in0Hi = absIn0 >> 16U; in0Lo = absIn0 & 65535U; in1Hi = absIn1 >> 16U; absIn0 = absIn1 & 65535U; productHiLo = in0Hi * absIn0; productLoHi = in0Lo * in1Hi; absIn0 *= in0Lo; absIn1 = 0U; in0Lo = (productLoHi << /*MW:OvBitwiseOk*/ 16U) + /*MW:OvCarryOk*/ absIn0; if (in0Lo < absIn0) { absIn1 = 1U; }
absIn0 = in0Lo; in0Lo += /*MW:OvCarryOk*/ productHiLo << /*MW:OvBitwiseOk*/ 16U; if (in0Lo < absIn0) { absIn1++; }
absIn0 = (((productLoHi >> 16U) + (productHiLo >> 16U)) + in0Hi * in1Hi) + absIn1; if (!((in0 == 0) || ((in1 == 0) || ((in0 > 0) == (in1 > 0))))) { absIn0 = ~absIn0; in0Lo = ~in0Lo; in0Lo++; if (in0Lo == 0U) { absIn0++; } }
*ptrOutBitsHi = absIn0; *ptrOutBitsLo = in0Lo; }
int32_T mul_s32_hiSR(int32_T a, int32_T b, uint32_T aShift) { uint32_T u32_chi; uint32_T u32_clo; mul_wide_s32(a, b, &u32_chi, &u32_clo); return (int32_T)u32_chi >> aShift; }
/* Model step function */ void Average_step(RT_MODEL_Average_T *const Average_M, int8_T Average_U_In1 [50000], int8_T *Average_Y_Out1) { int32_T i; int32_T rtb_SumofElements;
/* Sum: '<S1>/Sum of Elements' incorporates: * Inport: '<Root>/In1' */ rtb_SumofElements = Average_U_In1[0]; for (i = 0; i < 49999; i++) { rtb_SumofElements += Average_U_In1[i + 1]; }
/* End of Sum: '<S1>/Sum of Elements' */
/* Outport: '<Root>/Out1' incorporates: * Gain: '<S1>/Gain' */ *Average_Y_Out1 = (int8_T)mul_s32_hiSR(351843721, rtb_SumofElements, 12U); UNUSED_PARAMETER(Average_M); }
/* Model initialize function */ void Average_initialize(RT_MODEL_Average_T *const Average_M, int8_T Average_U_In1[50000], int8_T *Average_Y_Out1) { /* Registration code */
/* external inputs */ (void)memset(&Average_U_In1[0], 0, 50000U * sizeof(int8_T));
/* external outputs */ (*Average_Y_Out1) = 0; UNUSED_PARAMETER(Average_M); }
/* Model terminate function */ void Average_terminate(RT_MODEL_Average_T *const Average_M) { /* (no terminate code required) */ UNUSED_PARAMETER(Average_M); }
/* * File trailer for generated code. * * [EOF] */
По коду можно сказать, что матлаб сгенерировал хитрый умножитель на 1/50000. Почему - это зависит от того, что поддерживает, а что нет конкретная платформа Цитата Оч интересно, а каким таким образом Simulink вдруг гарантирует нам выполнение в реальном времени? Посмотрите первый комментарий в первом из сгенерированных файлов.
|
|
|
|
|
Mar 31 2017, 20:19
|

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

|
Цитата(syoma @ Mar 31 2017, 22:31)  Посмотрите первый комментарий в первом из сгенерированных файлов. Цитата Associating rt_OneStep with a real-time clock or interrupt service routine is what makes the generated code "real-time". Они над вами смеются. Заметили скобочки? Прочитайте весь комментарий. Они оставляют за собой право сделать "Overrun" и посылают вас самих это расхлебывать. Причем флаг "Overrun" оставили статическим внутри функции. Феерично! Так что не надо нам этих фэйков. Цитата(Lagman @ Mar 31 2017, 19:16)  Я ее как раз и не стал использовать, только потому, что она очень дорого выходит для штучных коммерческих изделий. Не знаю, я делаю штучные и коммерческие, я мэйкер. Мне бесплатно.
|
|
|
|
|
Mar 31 2017, 20:26
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата(AlexandrY @ Mar 31 2017, 22:17)  Они оставляют за собой право сделать "Overrun" и посылают вас самих это расхлебывать. А как вы предлагаете расхлебывать ситуацию в реальном времени, если разработанная вами функция не выполнится за заданное время? Цитата Причем флаг "Overrun" оставили статическим внутри функции. Феерично! А в чем проблема? rt_OneStep в примере предлагается вызывать в прерывании от таймера. Во время исполнения модельного кода флаг Overrun ставится в true, а после завершения сбрасывается. Если следующее прерывание от таймера произойдет до окончания исполнения модельного кода, факт overrun ловится и делай, сам, что считаешь нужным. Вообще-то ert_main.c - это всего лишь пример, как можно запустить функцию на исполнение в реальном времени без ОСРВ. Его можно без проблем изменять по своему усмотрению.
|
|
|
|
|
Mar 31 2017, 20:37
|

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

|
Цитата(syoma @ Mar 31 2017, 23:26)  А как вы предлагаете расхлебывать ситуацию в реальном времени, если разработанная вами функция не выполнится за заданное время? Никак, в Simulink вы её не расхлебаете и даже не узнаете о ней. Симулинк будет тупо раз за разом перезаписывать свои заглушки поверх ваших правок. Его код предназначен для устойчивой среды исполнения на базе RTOS уже сделанной в микроконтроллере. Вы же так и делаете. Используете vxWorks, а тут подсовываете надуманную лабуду.
|
|
|
|
|
Apr 3 2017, 19:49
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Цитата(TigerSHARC @ Apr 3 2017, 21:11)  Интересно сравнить, где "красивше" будет реализация такой нехитрой задачи: прерывание вызывается раз в 1мс, после десяти прерываний необходимо вызвать функцию, после десяти вызовов функции вызвать другую функцию.
с while(1), все понятно: заводим 2 глобальных счетчика и вперед щелкать инкременты в прерывании. С RTOS нешто проще как-то? Как вы собираетесь вызывать через 10 прерываний функцию? Если без ОСРВ то при вызове функции из прерывания вы будет находиться так же в прерывании, если не придумаете другой механизм вызова этой функции. Если с ОСРВ то будет то же самое (только вне прерывания) после 10 инкрементов в прерывании будет передано (например сообщение для вашей функции которая уже будет называться задачей и ожидать это сообщение) сообщение и если приоритет этой задачи (вашей функции) будет главным то по выходу из прерывания, планировщик переключит выполнение программы на эту функцию. Но вся эта магия приобретает интерес когда у вас будет несколько параллельных задач, например обработка АЦП в реальном времени (цифровая фильтрация), передача параметров по modbus и вывод значений на экран.
|
|
|
|
|
Apr 4 2017, 11:00
|
Знающий
   
Группа: Свой
Сообщений: 875
Регистрация: 28-10-05
Пользователь №: 10 245

|
Добавлю к словам Baser'a Цитата(Zelepuk @ Apr 4 2017, 09:20)  Зачем в прерывании вызывать функцию? обычно в прерывании дергаем флаг, а в цикле while(1) опрашиваем его. Что бы реакция МК была приближена к "мгновенной реакции", в ОСРВ это называется время реакции системы. А так можно все делать и без ОСРВ только это будет тяжелей поддерживать и координировать взаимосвязь и время работы "функций" в вашей программе.
|
|
|
|
|
Apr 4 2017, 19:28
|

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

|
Цитата(TigerSHARC @ Apr 4 2017, 22:00)  Мгновенная реакция - это конечно здорово, если нужно, например битик выставить в регистр, но FFT вы тоже считать в прерывании будете?  Да, именно в прерывании очень удобно делать FFT. Поскольку длительность всех прерываний автоматически логится SWO трассером и ведется статитстика. В системах жесткого реального времени самое важное - это профайлинг, а не RTOS, прерывания или что-то еще. А тут вы профайлинг получаете не пошевелив даже пальцем . У любого ARM-а есть туча свободных векторов прерываний и есть достаточное количество приоритетов у прерываний. Так что делать FFT в прерываниях я бы даже рекомендовал. Под RTOS типа Micrium OS такая концепция отлично ложится. Они кстати сегодня разослали предложение скачать триальную версию на 45 дней с Micrium Platform Builder.
|
|
|
|
|
Apr 5 2017, 10:58
|

Знающий
   
Группа: Свой
Сообщений: 779
Регистрация: 9-10-04
Из: Россия, Пермь
Пользователь №: 828

|
Решил не создавать новую тему, а здесь спросить: Никогда не пользовался setjmp/longjmp для сохранения под Cortex M3,4 контекста - возможно ли сделать так же красиво, как по ссылке: setjmp/longjmp AVRХотелось, если можно с примером кода (различие AVR/ARM). Или как в простой AVR-ской CoOS (файл в приложении) использование setjmp/longjmp: Какие компиляторы под ARM Cortex M3,4, GNU GCC, IAR... переваривают такое?
Прикрепленные файлы
COOS.rar ( 2.89 килобайт )
Кол-во скачиваний: 10
|
|
|
|
|
Apr 7 2017, 06:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(Zelepuk @ Mar 31 2017, 10:52)  Планируется разработка измерительного прибора .....
(1) Дело в том что нужно часто давать сигналы готовности данных на разных ступенях алгоритма. Использовать флаги - глобальные переменные неудобно (их будет слишком много).
(2) Сообщить, какие "более красивые подходы" для этого используются. например на микрокотнтроллере можно использовать ОСРВ и ее средства взаимодействия между задачами,
(3) а как быть когда нужно сделать демо-проект на PC (для последующего переноса на МК)?
(4) Все это выглядит ужасно в бесконечном цикле. (1) организуйте для глобальных данных одну структуру. Если не хотите уходить от "глобализации" Работать со всеми глоб. данными можно через один указатель на нее. (2) "красиво" можно сделать и без ОС. Зависит от сложности задачи и целесообразности использования ОС. Многие ОС для МК имеют "порты" под PC/x86 (3) Проект для контроллера надо изначально писать с расчетом на "переносимость" - на уровне компиляторов для MK и PC. В PC прокт компилировать-запускать в своем "эмуляторе". (например вывод на SPI заменить на вывод в файл или консоль) (4) Если "главный цикл" в основе Вас устраиевает - посмотрите на оболочку protothread Dunkless. ОНО работает-компилируется и на MK, и на PC (проверено). По-сути это оболочка для цикла.
|
|
|
|
|
Apr 8 2017, 05:06
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Zelepuk @ Mar 31 2017, 10:52)  Все это выглядит ужасно в бесконечном цикле.
Подскажите, как сделать грамотно. Не знаю, грамотно или нет, но все, что вы описали, а меня в главном цикле выглядит как Код ProcessADC(&adc); где реализован конечный автомат, работающий с АЦП и привязанный к конкретной структуре с набором параметров. Естественно, никаких заднржек, ожиданий и тд. - атомарное действие и возврат глобально объявляется структура adc (или несколько, если многоканальная система), а буфера и прочую требуху можно (нужно) вынести в отдельный модуль и объявить static, чтобы не лазить туда грязными ручками (и ножками) буфера тоже в виде структур с необходимыми параметрами (включая указатели на обработчики). и вообще все это плавно приводит к необходимости перехода на с++, т.к.там это все реализуется естественным образом без ручных костылей. а мэйн будет выглядеть так: Код Init(); while(1){ ClearWDT(); ProcessADC(&adc); ProcessData(&data); Poll(&interface); ProcessComand(&interface); } можно, конечно, сделать из батона троллейбус примотать сюда РТОС, но зачем?
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Apr 8 2017, 08:16
|
Знающий
   
Группа: Свой
Сообщений: 688
Регистрация: 4-09-09
Пользователь №: 52 195

|
Цитата(MrYuran @ Apr 8 2017, 08:06)  Не знаю, грамотно или нет, но все, что вы описали, а меня в главном цикле выглядит как Код ProcessADC(&adc); а мэйн будет выглядеть так: Код Init(); while(1){ ClearWDT(); ProcessADC(&adc); ProcessData(&data); Poll(&interface); ProcessComand(&interface); } можно, конечно, сделать из батона троллейбус примотать сюда РТОС, но зачем? тогда вы должны быть уверены, что время выполнения Poll(&interface); и ProcessComand(&interface); детерминировано. Иначе возможны пропуски данных от ацп. Цитата(MrYuran @ Apr 8 2017, 08:06)  можно, конечно, сделать из батона троллейбус примотать сюда РТОС, но зачем? РТОС нужна для выставления приоритета задач. У вас бы ProcessADC(&adc) имел наивысший приоритет. Наверное, с РТОС проще работать, если задач становится с десяток или больше...
|
|
|
|
|
Apr 8 2017, 15:17
|
Знающий
   
Группа: Свой
Сообщений: 688
Регистрация: 4-09-09
Пользователь №: 52 195

|
Цитата(MrYuran @ Apr 8 2017, 12:18)  Скорее, если над проектом работает десяток взаимозаменяемых студентов и нет времени каждому объяснять, что почем. Каждый пишет свой линейный кусочек, как учили в школе. Как удачно однажды кто-то брякнул, снижается порок вхождения  Далеко не только студенты пишут с использованием ртос. С ртос программу гараздо проще модифицировать. Хотя конечно если человек работает и хочет быть уверен что его не уволят так как исходный код прошивок может читать только он - тогда наверное лучше не использовать ртос. Здесь в начале темы кто-то ссылку давал на статью хабра. Там хорошо описано требование использовать ртос. Я видел программы где нужно было синхронизировать до 100 различных событий. Это все надо как- то синхронизировать. Зачем изобретать свой велосипед? Программа была написана на dsp/bios.
|
|
|
|
|
Apr 8 2017, 19:02
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(MrYuran @ Apr 8 2017, 11:18)  Скорее, если над проектом работает десяток взаимозаменяемых студентов и нет времени каждому объяснять, что почем. Каждый пишет свой линейный кусочек, как учили в школе. Ну-ну... Очевидно, что вы пишете только простые программы. Представьте, что в вашей ProcessData() возможны моменты времени, когда требуется ей потратить много тактов CPU (например - прогнать данные через тяжёлый фильтр), а в ProcessADC() - необходима быстрая реакция на какие-то события (и нельзя вынести в ISR). Что будете делать в вашем суперцикле? Другой случай: Требуется энергосбережение и программа большую часть времени спит, просыпаясь только для обработки событий. Событий много, события составляют последовательность событий (событие1, за ним сбытие2, событие3, и т.п - это всё цепочка последовательных событий для одной задачи; у других задач - свои цепочки событий). Как будете обрабатывать их вашим суперциклом? При любом событии будете проходить весь цикл, все автоматы состояний для каждой из цепочек? В случае РТОС будет разбужена только одна задача, которая отвечает за обработку данного события (одной цепочки), которая восстановит контекст в точку обработки событияN цепочки M, обработает его, контекст сохранится в новой точке программы и CPU опять уйдёт в сон. Суперцикл годен только для сравнительно простых программ. Скорее программок. Программиста, пытающегося писать большие и сложные программные комплексы реального времени, с асинхронной реакцией на много разноприоритетных событий, да ещё когда условия задачи периодически меняются и дополняются, лучше сразу уволить. Иначе, когда вдруг потребуется добавить в устройство совсем небольшой новый функционал обработки какой-то периферии например и окажется вдруг, что нужно весь этот суперцикл переписать.
|
|
|
|
|
Apr 8 2017, 19:51
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата Очевидно, что вы пишете только простые программы. Может хватит со своими очевидно? Были тут такие уже... Цитата Представьте... Представьте, что с суперциклом ничего представлять не надо. Все процедуры в цикле четко заданы и время исполнения в худшем случае представит собой простую сумму времен исполнения всех функций, входящих в суперцикл, которую легко просчитать и протестировать и в итоге гарантировать определенное время реакции при любых вариантах событий. А с вашими неопределенно когда возникающими прерываниями как считать? Сколько их будет за конкретное время? Как вы будете это тестировать и гарантировать?
|
|
|
|
|
Apr 9 2017, 08:30
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(syoma @ Apr 8 2017, 22:51)  . . . . Представьте, что с суперциклом ничего представлять не надо. Все процедуры в цикле четко заданы и время исполнения в худшем случае представит собой простую сумму времен исполнения всех функций, входящих в суперцикл, . . . . Я конечно извиняюсь, что влез, но действительно не все очевидно. То, с чем долбусь я. Есть 2 реализации проекта - на цикле на на RTOS (scmRTOS, freeRTOS) Блок работы с внешней флеш-памятью. После подачи команды на флеш (запись, стирание) флеш работает асинхронно. И таймауты на эту работу не детерменированы. При реализации на ОС код намного читабельнее и логичнее чем на цикле (в цикле приходится работать с флагами и прокручивать основной цикла на время ожидания ) В ОС . . . . while( !CompleteFlash() ) Sleep(100); . . . . Как альтернатива - использовать ОС в кооперативном режиме (в freeRTOS - coroutine)
|
|
|
|
|
Apr 9 2017, 08:59
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(syoma @ Apr 8 2017, 21:51)  Все процедуры в цикле четко заданы и время исполнения в худшем случае представит собой простую сумму времен исполнения всех функций, входящих в суперцикл, которую легко просчитать и протестировать и в итоге гарантировать определенное время реакции при любых вариантах событий. Посчитали и оказалось, что в одной из веток алгоритма иногда надо выполнить тяжёлый фильтр (когда накопится достаточное кол-во сэмплов), а в другой - БПФ, тоже иногда. При этом в другой функции надо быстро реагировать на какие-то события, время этой реакции - должно быть много меньше времени выполнения фильтра или БПФ. Ваши действия? Что будете делать с вашим "легко просчитанным временем"?? С РТОС я БПФ и фильтр легко вынесу в низкоприоритетную задачу и решу проблему. А что делать с суперциклом? Цитата(k155la3 @ Apr 9 2017, 10:30)  И таймауты на эту работу не детерменированы. При реализации на ОС код намного читабельнее и логичнее чем на цикле (в цикле приходится работать с флагами и прокручивать основной цикла на время ожидания ) Это понятно. Вот для таких случаев как раз удобно использовать ОС. Просто некоторые люди не имеют дела с задачами сложнее "подрыгать парой ног и передать пару байт в UART" им сложно представить, что в системах реального времени приходится одновременно обслуживать сразу множество устройств с кучей разных состояний и событий. Просчитать все возможные времена просто нереально (да и бессмысленно). Зато можно разбить процессы по приоритетам на более и менее важные. Цитата(k155la3 @ Apr 9 2017, 10:30)  Как альтернатива - использовать ОС в кооперативном режиме (в freeRTOS - coroutine) Это усложнит код программы. Вам придётся каждую функцию приспосабливать под вашу ОС, просчитывать время её выполнения и пр. Но зачем? Мартышкин труд. Если можно использовать вытесняющую ОС. Другое дело - когда не хаватает ресурсов (памяти например для стеков задач), тогда можно объединить некоторые операции в пределах одной задачи вытесняющей ОС. Я нередко делаю так (чтобы сократить объём необходимой памяти под стеки задач): объединяю несколько (2-3) процессов с примерно одним временем реакции и временем выполнения в один суперцикл и помещаю его внутрь одной задачи вытесняющей ОС. Процессы с другим временем выполнения (и с другой требуемой скоростью реакции на события) - в другую задачу, с другим приоритетом.
|
|
|
|
|
Apr 9 2017, 09:52
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(jcxz @ Apr 9 2017, 11:59)  . . . Это усложнит код программы. Вам придётся каждую функцию приспосабливать под вашу ОС, просчитывать время её выполнения и пр. Но зачем? Мартышкин труд. Если можно использовать вытесняющую ОС. Другое дело - когда не хаватает ресурсов (памяти например для стеков задач), тогда можно объединить некоторые операции в пределах одной задачи вытесняющей ОС. . . . В моем случае приходится извращаться, так как в максимальном приоритете - экономичность (батарейное питание). А вытесняющая OC подразумевает тики для планировщика. В нашей реализации тикало с периодом 16 мс - очень не экономично. Можно конечно переключать этот период (на 250мс) для неактивно-рабочего режима (без оператора). В общем, эта тема у меня недостаточно раскурена.
|
|
|
|
|
Apr 9 2017, 10:40
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(TigerSHARC @ Apr 8 2017, 18:17)  Здесь в начале темы кто-то ссылку давал на статью хабра. Там хорошо описано требование использовать ртос. В какой статье какого кодекса значится описанное в статье требование? На ту статью был дан адекватный ответ другой статьей. ( Альтернативный подход к проектированию ПО для Embedded)
|
|
|
|
|
Apr 9 2017, 15:26
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(k155la3 @ Apr 9 2017, 11:52)  В моем случае приходится извращаться, так как в максимальном приоритете - экономичность (батарейное питание). А вытесняющая OC подразумевает тики для планировщика. Не обязательно. В момент времени когда нет полезной нагрузки (управление передаётся в фоновую IDLE-задачу) можно просмотреть список задач и объектов синхронизации (майлбоксы, мьютексы и т.п.), найти из всех них ближайшее время пробуждения и уснуть до этого времени. А ещё лучше - сделать группировку времён сна разных задач ОС в более крупные интервалы, в которые можно уйти в более глубокий сон. Я так делал в одном батарейном проекте с uCOS. Делал надстройку над функциями ОС - каждая задача вызывающая объект с синхронизации с таймаутом или просто уходящая в IDLE на N тиков, сообщала при этом вызове минимально- и максимально-возможное время этого IDLE-состояния которое ей требуется. Это всё запоминалось и когда шедулер обнаруживал момент простоя всей системы, он анализировал эти времена и выбирал оптимальное время сна, так чтобы максимально оптимально уложиться в интервалы требований для разных задач (не превышая максимально-допустимый сон для каждой задачи и стараясь максимально увеличить время сна). Если полученное значение интервала сна получалось менее какого-то порога, то просто выполнялась WFE, если более - выполнялся вход в глубокий сон (вход и выход в который естественно дольше).
|
|
|
|
|
May 22 2017, 01:14
|
Частый гость
 
Группа: Участник
Сообщений: 91
Регистрация: 3-07-11
Пользователь №: 66 028

|
Добрый день, для своих программ использовал Switch подход, но до пары до времени... Понадобилась спортировать свою программу на другую плату, а там почти вся периферия сидит на I2C а это 2 термодатчика, календарь, расширитель порта->(Светодиоды,Кнопки и LCD). И все это должно работать и отрабатывать замыкания линий и тд, и в случае если отвалится термодатчик то LСD Должен работать. Сначала пошёл городить Switch на это все, но получилось как-то запутано, и ешё не нравилось, что есть куча проходов функций, пока там до LCD дойдет. Ну и соответственно с обработкой аварии были проблемы. Так что сейчас решил написать свою ОС, с минимальными возможностями сохранения и переключения контента, и во всех задержках(ожидания флага или времени LCD) поставить переключение на другие задачи. Сделал пару процессов, и теперь думаю над тем как разделить опрос медленных процессов(Термодатчика) от быстрых(опрос клавиатуры(матричной)).
Но все же интересно, если другие способы это все организовать?
А и еше как можно ОС протестировать и погонять, что она не разваливается?
|
|
|
|
|
May 22 2017, 06:24
|
Профессионал
    
Группа: Свой
Сообщений: 1 123
Регистрация: 8-03-09
Из: Днепр
Пользователь №: 45 848

|
Цитата(pokk @ May 22 2017, 04:14)  . . . Но все же интересно, если другие способы это все организовать? А и еше как можно ОС протестировать и погонять, что она не разваливается? Если все ф-ии системы ограничены тем, что Вы указали, то можно обойтись и главным циклом, переключать контекст не надо. "Планировщик" делаете на таймере и CCR - разбиваю период главного цикла на нужное кол-во фаз с детерминированным времением исполнения каждой. Ожидание и приоритеты реализуются "прокруткой" главного цикла, софт-таймерами и флагами. Мне на форуме посоветовали protothreads - тотже "упакованный" while - switch-case. Если нужно переключение контекста - попробуйте scmRTOS - вполне себе работала у меня и с прерываниями и с I2C, и с SPI, и с USART.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|