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

ModBus и Keil RTX

Есть у меня задача реализовать библиотеку для ModBus чтобы она работала через RS232 и RS485 чтобы могла легким движением руки быть ASCII и RTU и чтобы можно быстро ее прикрутить к любому UART на контролере коих на моем микроконтроллере три(согласно CMSIS для Cortex как я понимаю). Все это делаю я для микроконтроллера Luminary с помощью Keil если вдруг кому интересно. Так вот в чем собственно вопрос хочется чтобы библиотека могла работать как отдельно так и вместе с RTOS я для себя выбрал Keil-RTX но дело в том что, то что я написал сам пакет собирает(но необрабатывает) в прирывании а как я почитал в кейловской книге RL-ARM Getting Started раздел Interrupt Handling что RTOS не очень любят а вернее сказать вобще не любят что то долго делать в прерывании что как я понимаю плохо сказывается на шедулере так как я пишу системы реального времени то это может быть критично. Так вот оправдан ли такой подход или если я вдруг хочу использовать RTOS то мне придется переписывать код чтобы он был под нее и заточен то есть отдельную библиотеку для RTOS.

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


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

Обычно любую работу с UART в Keil RTX я разделяю на две части :

 

1) в прерывании я просто отправляю полученные данные в mailbox (да, несколько неэффективно по памяти).

// указатель на mailbox для UART2 модуля 
u32* uart2_mbx;

/* Обработчик прерывания UART2 */
void uart2_isr (void) __irq 
{
  if (isr_mbx_check(uart2_mbx) != 0) isr_mbx_send(uart2_mbx, (void *)U2RBR);    // если uart2_mbx не переполнен послали в uart2_mbx принятый байт
  VICVectAddr = 0;                                                              // завершили прерывание
}

 

2) делаю отдельную задачу для обработки принятых данных

/* Задача приема пакета wake */
__task void task_wake(void) 
{
 u32 data;

 os_mbx_init(wake_mbx_byte, sizeof(wake_mbx_byte));                            // инициализация mailbox для принятых байт 
 os_mbx_init(wake_mbx_pack, sizeof(wake_mbx_pack));                            // инициализация mailbox для полученных пакетов 

 uart2_init(WAKE_BAUDRATE, (u32 *)wake_mbx_byte);                              // инициализация UART2

 PINSEL4 &= ~((u32)3 << 26);                                                   // разрешили WAKE_DIR пин
 FIO2DIR |= WAKE_DIR;                                                          // установили WAKE_DIR пин как выход
 FIO2CLR |= WAKE_DIR;                                                          // установили направление - ПРИЕМ

 pack.hdr = WAKE_FEND;

 while (1)
 {
   /* Прием FEND */
   os_mbx_wait(wake_mbx_byte, (void *)&data, 0xFFFF);                          // бесконечное ожидание FEND
   if (data != WAKE_FEND) continue;                                            // выход если пришел не FEND
   /* Прием ADR */
   if ((data = get_stuf()) == WAKE_ERROR) continue;                            // выход при ошибке приема ADR
   pack.adr = data & 0x7F;                                                     // сохранили ADR
   /* Прием CMD */
   if ((data = get_stuf()) > 0x7F) continue;                                   // выход при ошибке приема CMD 
   pack.cmd = data;                                                            // сохранили CMD
   /* Прием NUM */
   if ((data = get_stuf()) == WAKE_ERROR) continue;                            // выход при ошибке приема NUM
   pack.num = data;                                                            // сохранили NUM
   /* Прием DAT */
   pack.tmp = 0;                                                               // сбросили счетчик принятых данных
   while (pack.tmp < pack.num)                                                 // пока не приняты все данные
   {
     if ((data = get_stuf()) == WAKE_ERROR) break;                             // прекращаем прием данных при ошибке
     pack.dat[pack.tmp++] = data;                                              // сохранили принятые данные
   }
   if (pack.tmp != pack.num) continue;                                         // выход если не все данные прияты
   /* Прием CRC */
   if ((data = get_stuf()) == WAKE_ERROR) continue;                            // выход при ошибке приема CRC
   pack.dat[pack.num] = data;                                                  // сохранили CRC
   /* Проверка целосности пакета */
   pack.tmp = CRC8(0x18, 0xDE, &pack.hdr, pack.num + 4);                       // считаем CRC пакета
   if (pack.dat[pack.num] == pack.tmp)                                         // если расчетное CRC совпадает с принятым
   {
     if (os_mbx_check(wake_mbx_pack) != 0) os_mbx_send(wake_mbx_pack, (void *)&pack, 0);// если wake_mbx_pack не переполнен посылаем принятый пакет
#ifdef ERROR_HANDLING  
     else os_mbx_send(error_mbx, (void *)ERROR_WAKE_MBX_OVR, WAKE_TIMEOUT);    // иначе отправляем ошибку переполнения wake_mbx_pack   
#endif
   }
 }
}

 

Очень удобно и наглядно получается

 

P.S. Протокол WAKE я использую несколько модифицированный.

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


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

Ну именно так и советуют поступать в документации по Keil RTX(делать высокоприоритетную задачу и будить ее по какому нибуть эвенту который генериться в UART ISR при приходе символа) но от что меня беспокоит в таком случае и проблема в дополнительных затратах в ресурсов тут менее приоритетна допустим мы работаем на скорости 115200 б/c фрейм для одного байта = 1старт бит + 8 бит данных + 1 паритет + 1 стоп бит = 11 бит для передачи одного байта период соответственно равен T = около 10 мкс тость 20 мкс для передачи 2х символов а для скоростей повыше и того меньше будет. В моем мк к примеру UART аж до мегабита раскочегарить можно если те ошибаюсь боюсь что при таком раскладе и 5 пакетов будет принимать только 1 нормально или может я не прав? С чего такие опасения я раскажу я тут писал ModBus TCP(на lwIP) и как заглянул в Ethernet ISR Handler а код там будь здоров или кто то в критическую секцию зашел от мы и начали пропускать наши байты в UART Thread.

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


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

Ну именно так и советуют поступать в документации по Keil RTX(делать высокоприоритетную задачу и будить ее по какому нибуть эвенту который генериться в UART ISR при приходе символа) но от что меня беспокоит в таком случае и проблема в дополнительных затратах в ресурсов тут менее приоритетна допустим мы работаем на скорости 115200 б/c фрейм для одного байта = 1старт бит + 8 бит данных + 1 паритет + 1 стоп бит = 11 бит для передачи одного байта период соответственно равен T = около 10 мкс тость 20 мкс для передачи 2х символов а для скоростей повыше и того меньше будет. В моем мк к примеру UART аж до мегабита раскочегарить можно если те ошибаюсь боюсь что при таком раскладе и 5 пакетов будет принимать только 1 нормально или может я не прав? С чего такие опасения я раскажу я тут писал ModBus TCP(на lwIP) и как заглянул в Ethernet ISR Handler а код там будь здоров или кто то в критическую секцию зашел от мы и начали пропускать наши байты в UART Thread.

При больших скоростях, как мне кажется, лучше уже пользоваться ПДП (если есть конечно). Принимать в буфер а затем уже адрес буфера передавать по mailbox. Собственно без ПДП логика та же: несколько буферов, по очереди прием в один ои них, потом передача по mailbox адреса. Принимающая задача естественно должна позаботиться об освобождении буфера.

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


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

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

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

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

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

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

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

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

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

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